Merge "Verify that the component is exported"
diff --git a/Android.bp b/Android.bp
index c0a70b9..2c550fd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -428,6 +428,15 @@
     name: "framework-minus-apex-intdefs",
     defaults: ["framework-minus-apex-defaults"],
     plugins: ["intdef-annotation-processor"],
+
+    // Errorprone and android lint will already run on framework-minus-apex, don't rerun them on
+    // the intdefs version in order to speed up the build.
+    errorprone: {
+        enabled: false,
+    },
+    lint: {
+        enabled: false,
+    },
 }
 
 // This "framework" module is NOT installed to the device. It's
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/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 1d92778..9a4323a 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -25,6 +25,6 @@
 
 hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
 
-ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/ktfmt_includes.txt ${PREUPLOAD_FILES}
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check -i ${REPO_ROOT}/frameworks/base/packages/SystemUI/ktfmt_includes.txt ${PREUPLOAD_FILES}
 
 ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
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 @@
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
index 3781b6d..03e5468 100644
--- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -257,7 +257,7 @@
         runShellCommand(String.format(
                 "cmd blob_store delete-blob --algo %s --digest %s --label %s --expiry %d --tag %s",
                 blobHandle.algorithm,
-                Base64.getEncoder().encode(blobHandle.digest),
+                Base64.getEncoder().encodeToString(blobHandle.digest),
                 blobHandle.label,
                 blobHandle.expiryTimeMillis,
                 blobHandle.tag));
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/surfaceflinger/AndroidTest.xml b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
index 0f3a068..11d1106 100644
--- a/apct-tests/perftests/surfaceflinger/AndroidTest.xml
+++ b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
@@ -44,21 +44,33 @@
         <option name="hidden-api-checks" value="false"/>
 
         <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
-        <option name="device-listeners" value="android.device.collectors.PerfettoListener,android.device.collectors.SimpleperfListener" />
+        <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener,android.device.collectors.SimpleperfListener" />
 
         <!-- 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(long, long, long)&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 -->
+        <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+        <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+        <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+        <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
     </test>
 
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
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 f4d0c05..f92c297 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -16,51 +16,182 @@
 
 package android.surfaceflinger;
 
+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;
 import androidx.test.filters.LargeTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+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;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Random;
+
 @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);
-    }
-    @Test
-    public void submitSingleBuffer() throws Exception {
-        SurfaceControl sc = mActivity.getChildSurfaceControl();
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        BufferFlinger bufferflinger = new BufferFlinger(BUFFER_COUNT, Color.GREEN);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        t.show(sc);
-
-        while (state.keepRunning()) {
-            bufferflinger.addBuffer(t, sc);
-            t.apply();
+        for (int i = 0; i < MAX_BUFFERS; i++) {
+            SurfaceControl sc = createSurfaceControl();
+            BufferFlinger bufferTracker = createBufferTracker(Color.argb(getRandomColorComponent(),
+                    getRandomColorComponent(), getRandomColorComponent(),
+                    getRandomColorComponent()));
+            bufferTracker.addBuffer(t, sc);
+            t.setPosition(sc, i * 10, i * 10);
         }
-        bufferflinger.freeBuffers();
+        t.apply(true);
+    }
+
+    @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++) {
+                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
+                mTransaction.show(mSurfaceControls.get(i));
+            }
+            mTransaction.apply(true);
+        }
+    }
+
+    @Test
+    public void multipleOpaqueBuffers() throws Exception {
+        for (int j = 0; j < sProfilingIterations; j++) {
+            for (int i = 0; i < MAX_BUFFERS; i++) {
+                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
+                mTransaction.show(mSurfaceControls.get(i)).setOpaque(mSurfaceControls.get(i), true);
+            }
+            mTransaction.apply(true);
+        }
+    }
+
+    @Test
+    public void geometryChanges() throws Exception {
+        int step = 0;
+        for (int i = 0; i < sProfilingIterations; i++) {
+            step = ++step % MAX_POSITION;
+            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
+            float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
+            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
+        }
+    }
+
+    @Test
+    public void geometryWithBufferChanges() throws Exception {
+        int step = 0;
+        for (int i = 0; i < sProfilingIterations; i++) {
+            step = ++step % MAX_POSITION;
+            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 {
+        for (int i = 0; i < sProfilingIterations; i++) {
+            SurfaceControl childSurfaceControl =  new SurfaceControl.Builder()
+                    .setName("childLayer").setBLASTLayer().build();
+            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 {
+        for (int i = 0; i < sProfilingIterations; i++) {
+            Bitmap screenshot =
+                    InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
+            screenshot.recycle();
+            mTransaction.apply(true);
+        }
+    }
+
+    @Test
+    public void layerScreenshot() throws Exception {
+        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 a9b2a31..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 getChildSurfaceControl() 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/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index f49cdbf..ab0ac5a 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1312,6 +1312,9 @@
          * Calling this method will override any requirements previously defined
          * by {@link #setRequiredNetwork(NetworkRequest)}; you typically only
          * want to call one of these methods.
+         * <p> Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+         * {@link JobScheduler} may try to shift the execution of jobs requiring
+         * {@link #NETWORK_TYPE_ANY} to when there is access to an un-metered network.
          * <p class="note">
          * When your job executes in
          * {@link JobService#onStartJob(JobParameters)}, be sure to use the
@@ -1742,6 +1745,7 @@
          *     <li>Bypass Doze, app standby, and battery saver network restrictions</li>
          *     <li>Be less likely to be killed than regular jobs</li>
          *     <li>Be subject to background location throttling</li>
+         *     <li>Be exempt from delay to optimize job execution</li>
          * </ol>
          *
          * <p>
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 632ecb2c..dfdb290 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -45,8 +45,23 @@
  * </p>
  * <p>
  * The framework will be intelligent about when it executes jobs, and attempt to batch
- * and defer them as much as possible. Typically if you don't specify a deadline on a job, it
+ * and defer them as much as possible. Typically, if you don't specify a deadline on a job, it
  * can be run at any moment depending on the current state of the JobScheduler's internal queue.
+ * </p>
+ * <p>
+ * Starting in Android version {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE},
+ * JobScheduler may try to optimize job execution by shifting execution to times with more available
+ * system resources in order to lower user impact. Factors in system health include sufficient
+ * battery, idle, charging, and access to an un-metered network. Jobs will initially be treated as
+ * if they have all these requirements, but as their deadlines approach, restrictions will become
+ * less strict. Requested requirements will not be affected by this change.
+ * </p>
+ *
+ * {@see android.app.job.JobInfo.Builder#setRequiresBatteryNotLow(boolean)}
+ * {@see android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)}
+ * {@see android.app.job.JobInfo.Builder#setRequiresCharging(boolean)}
+ * {@see android.app.job.JobInfo.Builder#setRequiredNetworkType(int)}
+ *
  * <p>
  * While a job is running, the system holds a wakelock on behalf of your app.  For this reason,
  * you do not need to take any action to guarantee that the device stays awake for the
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..b6d29aa 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;
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 9d36478..f1e13df 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
@@ -38,6 +38,7 @@
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArrayMap;
 
@@ -57,7 +58,9 @@
  * Drops constraint for TOP apps and lowers number of required constraints with time.
  */
 public final class FlexibilityController extends StateController {
-    private static final String TAG = "JobScheduler.Flexibility";
+    private static final String TAG = "JobScheduler.Flex";
+    private static final boolean DEBUG = JobSchedulerService.DEBUG
+            || Log.isLoggable(TAG, Log.DEBUG);
 
     /** List of all system-wide flexible constraints whose satisfaction is independent of job. */
     static final int SYSTEM_WIDE_FLEXIBLE_CONSTRAINTS = CONSTRAINT_BATTERY_NOT_LOW
@@ -260,6 +263,11 @@
                 return;
             }
 
+            if (DEBUG) {
+                Slog.d(TAG, "setConstraintSatisfied: "
+                       + " constraint: " + constraint + " state: " + state);
+            }
+
             final int prevSatisfied = Integer.bitCount(mSatisfiedFlexibleConstraints);
             mSatisfiedFlexibleConstraints =
                     (mSatisfiedFlexibleConstraints & ~constraint) | (state ? constraint : 0);
@@ -488,9 +496,6 @@
 
         /** Removes a JobStatus object. */
         public void remove(JobStatus js) {
-            if (js.getNumRequiredFlexibleConstraints() == 0) {
-                return;
-            }
             mTrackedJobs.get(js.getNumRequiredFlexibleConstraints()).remove(js);
         }
 
@@ -555,7 +560,7 @@
     class FlexibilityAlarmQueue extends AlarmQueue<JobStatus> {
         private FlexibilityAlarmQueue(Context context, Looper looper) {
             super(context, looper, "*job.flexibility_check*",
-                    "Flexible Constraint Check", false,
+                    "Flexible Constraint Check", true,
                     mMinTimeBetweenFlexibilityAlarmsMs);
         }
 
@@ -571,7 +576,20 @@
                 final long nextTimeElapsed =
                         getNextConstraintDropTimeElapsedLocked(js, earliest, latest);
 
+                if (DEBUG) {
+                    Slog.d(TAG, "scheduleDropNumConstraintsAlarm: "
+                            + js.getSourcePackageName() + " " + js.getSourceUserId()
+                            + " numRequired: " + js.getNumRequiredFlexibleConstraints()
+                            + " numSatisfied: " + Integer.bitCount(mSatisfiedFlexibleConstraints)
+                            + " curTime: " + nowElapsed
+                            + " earliest: " + earliest
+                            + " latest: " + latest
+                            + " nextTime: " + nextTimeElapsed);
+                }
                 if (latest - nowElapsed < mDeadlineProximityLimitMs) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "deadline proximity met: " + js.getUid());
+                    }
                     mFlexibilityTracker.adjustJobsRequiredConstraints(js,
                             -js.getNumRequiredFlexibleConstraints(), nowElapsed);
                     return;
@@ -581,7 +599,10 @@
                     removeAlarmForKey(js);
                     return;
                 }
-                if (latest - nextTimeElapsed < mDeadlineProximityLimitMs) {
+                if (latest - nextTimeElapsed <= mDeadlineProximityLimitMs) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "last alarm set: " + js.getUid());
+                    }
                     addAlarm(js, latest - mDeadlineProximityLimitMs);
                     return;
                 }
@@ -597,6 +618,7 @@
                 for (int i = 0; i < expired.size(); i++) {
                     JobStatus js = expired.valueAt(i);
                     boolean wasFlexibilitySatisfied = js.isConstraintSatisfied(CONSTRAINT_FLEXIBLE);
+
                     if (mFlexibilityTracker.adjustJobsRequiredConstraints(js, -1, nowElapsed)) {
                         scheduleDropNumConstraintsAlarm(js, nowElapsed);
                     }
@@ -717,6 +739,8 @@
                     if (mMinTimeBetweenFlexibilityAlarmsMs
                             != MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS) {
                         mMinTimeBetweenFlexibilityAlarmsMs = MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS;
+                        mFlexibilityAlarmQueue
+                                .setMinTimeBetweenAlarmsMs(MIN_TIME_BETWEEN_FLEXIBILITY_ALARMS_MS);
                         mShouldReevaluateConstraints = true;
                     }
                     break;
@@ -787,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: ");
@@ -797,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/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..4ba6957 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/EconomicPolicy.java
@@ -70,6 +70,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;
@@ -409,6 +410,8 @@
                 return "BG_RESTRICTED";
             case REGULATION_BG_UNRESTRICTED:
                 return "BG_UNRESTRICTED";
+            case REGULATION_FORCE_STOP:
+                return "FORCE_STOP";
         }
         return "UNKNOWN_REGULATION:" + Integer.toHexString(eventId);
     }
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 448a808..59d4ded 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -43,6 +43,7 @@
 import android.content.pm.PackageManagerInternal;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
 import android.os.Binder;
 import android.os.Handler;
@@ -163,6 +164,7 @@
     @GuardedBy("mLock")
     private final SparseArrayMap<String, Boolean> mVipOverrides = new SparseArrayMap<>();
 
+    private volatile boolean mHasBattery = true;
     private volatile boolean mIsEnabled;
     private volatile int mBootPhase;
     private volatile boolean mExemptListLoaded;
@@ -204,6 +206,15 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             switch (intent.getAction()) {
+                case Intent.ACTION_BATTERY_CHANGED: {
+                    final boolean hasBattery =
+                            intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, mHasBattery);
+                    if (mHasBattery != hasBattery) {
+                        mHasBattery = hasBattery;
+                        mConfigObserver.updateEnabledStatus();
+                    }
+                }
+                break;
                 case Intent.ACTION_BATTERY_LEVEL_CHANGED:
                     onBatteryLevelChanged();
                     break;
@@ -522,7 +533,9 @@
 
     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);
         }
     }
 
@@ -565,17 +578,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);
         }
     }
 
@@ -713,6 +724,12 @@
         return packages;
     }
 
+    private boolean isTareSupported() {
+        // TARE is presently designed for devices with batteries. Don't enable it on
+        // battery-less devices for now.
+        return mHasBattery;
+    }
+
     @GuardedBy("mLock")
     private void loadInstalledPackageListLocked() {
         mPkgCache.clear();
@@ -731,6 +748,7 @@
 
     private void registerListeners() {
         final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
         filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
         filter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
         getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
@@ -765,6 +783,7 @@
             return;
         }
         synchronized (mLock) {
+            mCompleteEconomicPolicy.setup(mConfigObserver.getAllDeviceConfigProperties());
             loadInstalledPackageListLocked();
             final boolean isFirstSetup = !mScribe.recordExists();
             if (isFirstSetup) {
@@ -796,6 +815,18 @@
         synchronized (mLock) {
             registerListeners();
             mCurrentBatteryLevel = getCurrentBatteryLevel();
+            // Get the current battery presence, if available. This would succeed if TARE is
+            // toggled long after boot.
+            final Intent batteryStatus = getContext().registerReceiver(null,
+                    new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+            if (batteryStatus != null) {
+                final boolean hasBattery =
+                        batteryStatus.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
+                if (mHasBattery != hasBattery) {
+                    mHasBattery = hasBattery;
+                    mConfigObserver.updateEnabledStatus();
+                }
+            }
         }
     }
 
@@ -803,10 +834,7 @@
         if (mBootPhase < PHASE_THIRD_PARTY_APPS_CAN_START || !mIsEnabled) {
             return;
         }
-        synchronized (mLock) {
-            mHandler.post(this::setupHeavyWork);
-            mCompleteEconomicPolicy.setup(mConfigObserver.getAllDeviceConfigProperties());
-        }
+        mHandler.post(this::setupHeavyWork);
     }
 
     private void onBootPhaseBootCompleted() {
@@ -985,7 +1013,7 @@
         @Override
         public void registerAffordabilityChangeListener(int userId, @NonNull String pkgName,
                 @NonNull AffordabilityChangeListener listener, @NonNull ActionBill bill) {
-            if (isSystem(userId, pkgName)) {
+            if (!isTareSupported() || isSystem(userId, pkgName)) {
                 // The system's affordability never changes.
                 return;
             }
@@ -1008,6 +1036,9 @@
 
         @Override
         public void registerTareStateChangeListener(@NonNull TareStateChangeListener listener) {
+            if (!isTareSupported()) {
+                return;
+            }
             mStateChangeListeners.add(listener);
         }
 
@@ -1180,11 +1211,10 @@
 
         private void updateEnabledStatus() {
             // User setting should override DeviceConfig setting.
-            // NOTE: There's currently no way for a user to reset the value (via UI), so if a user
-            // manually toggles TARE via UI, we'll always defer to the user's current setting
             final boolean isTareEnabledDC = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TARE,
                     KEY_DC_ENABLE_TARE, Settings.Global.DEFAULT_ENABLE_TARE == 1);
-            final boolean isTareEnabled = Settings.Global.getInt(mContentResolver,
+            final boolean isTareEnabled = isTareSupported()
+                    && Settings.Global.getInt(mContentResolver,
                     Settings.Global.ENABLE_TARE, isTareEnabledDC ? 1 : 0) == 1;
             if (mIsEnabled != isTareEnabled) {
                 mIsEnabled = isTareEnabled;
@@ -1268,6 +1298,10 @@
     }
 
     private void dumpInternal(final IndentingPrintWriter pw, final boolean dumpAll) {
+        if (!isTareSupported()) {
+            pw.print("Unsupported by device");
+            return;
+        }
         synchronized (mLock) {
             pw.print("Is enabled: ");
             pw.println(mIsEnabled);
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/abx/Android.bp b/cmds/abx/Android.bp
index 50a0b75..a832dea 100644
--- a/cmds/abx/Android.bp
+++ b/cmds/abx/Android.bp
@@ -1,4 +1,3 @@
-
 package {
     default_applicable_licenses: ["frameworks_base_cmds_abx_license"],
 }
@@ -18,7 +17,7 @@
 
 java_binary {
     name: "abx",
-    wrapper: "abx",
+    wrapper: "abx.sh",
     srcs: ["**/*.java"],
     required: [
         "abx2xml",
@@ -28,10 +27,10 @@
 
 sh_binary {
     name: "abx2xml",
-    src: "abx2xml",
+    src: "abx2xml.sh",
 }
 
 sh_binary {
     name: "xml2abx",
-    src: "xml2abx",
+    src: "xml2abx.sh",
 }
diff --git a/cmds/abx/abx b/cmds/abx/abx.sh
similarity index 100%
rename from cmds/abx/abx
rename to cmds/abx/abx.sh
diff --git a/cmds/abx/abx2xml b/cmds/abx/abx2xml
deleted file mode 100755
index 0a9362d..0000000
--- a/cmds/abx/abx2xml
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/system/bin/sh
-export CLASSPATH=/system/framework/abx.jar
-exec app_process /system/bin com.android.commands.abx.Abx "$0" "$@"
diff --git a/cmds/abx/abx b/cmds/abx/abx2xml.sh
similarity index 100%
copy from cmds/abx/abx
copy to cmds/abx/abx2xml.sh
diff --git a/cmds/abx/xml2abx b/cmds/abx/xml2abx
deleted file mode 100755
index 0a9362d..0000000
--- a/cmds/abx/xml2abx
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/system/bin/sh
-export CLASSPATH=/system/framework/abx.jar
-exec app_process /system/bin com.android.commands.abx.Abx "$0" "$@"
diff --git a/cmds/abx/abx b/cmds/abx/xml2abx.sh
similarity index 100%
copy from cmds/abx/abx
copy to cmds/abx/xml2abx.sh
diff --git a/cmds/am/Android.bp b/cmds/am/Android.bp
index 7bb9675..c6cc7c5 100644
--- a/cmds/am/Android.bp
+++ b/cmds/am/Android.bp
@@ -30,7 +30,7 @@
 
 java_binary {
     name: "am",
-    wrapper: "am",
+    wrapper: "am.sh",
     srcs: [
         "src/**/*.java",
         "proto/**/*.proto",
diff --git a/cmds/am/am b/cmds/am/am.sh
similarity index 100%
rename from cmds/am/am
rename to cmds/am/am.sh
diff --git a/cmds/appops/Android.bp b/cmds/appops/Android.bp
index 80f8ec6..538ae94 100644
--- a/cmds/appops/Android.bp
+++ b/cmds/appops/Android.bp
@@ -19,5 +19,5 @@
 
 sh_binary {
     name: "appops",
-    src: "appops",
+    src: "appops.sh",
 }
diff --git a/cmds/appops/appops b/cmds/appops/appops.sh
similarity index 100%
rename from cmds/appops/appops
rename to cmds/appops/appops.sh
diff --git a/cmds/appwidget/Android.bp b/cmds/appwidget/Android.bp
index 8049038..cd439e2 100644
--- a/cmds/appwidget/Android.bp
+++ b/cmds/appwidget/Android.bp
@@ -19,6 +19,6 @@
 
 java_binary {
     name: "appwidget",
-    wrapper: "appwidget",
+    wrapper: "appwidget.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/appwidget/appwidget b/cmds/appwidget/appwidget.sh
similarity index 100%
rename from cmds/appwidget/appwidget
rename to cmds/appwidget/appwidget.sh
diff --git a/cmds/bmgr/Android.bp b/cmds/bmgr/Android.bp
index 14beb55..a85669a 100644
--- a/cmds/bmgr/Android.bp
+++ b/cmds/bmgr/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "bmgr",
-    wrapper: "bmgr",
+    wrapper: "bmgr.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/bmgr/bmgr b/cmds/bmgr/bmgr.sh
similarity index 100%
rename from cmds/bmgr/bmgr
rename to cmds/bmgr/bmgr.sh
diff --git a/cmds/bu/Android.bp b/cmds/bu/Android.bp
index 5b4ec31..b61a7a6 100644
--- a/cmds/bu/Android.bp
+++ b/cmds/bu/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "bu",
-    wrapper: "bu",
+    wrapper: "bu.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/bu/bu b/cmds/bu/bu.sh
similarity index 100%
rename from cmds/bu/bu
rename to cmds/bu/bu.sh
diff --git a/cmds/content/Android.bp b/cmds/content/Android.bp
index c70d01e..0dd0f03 100644
--- a/cmds/content/Android.bp
+++ b/cmds/content/Android.bp
@@ -19,6 +19,6 @@
 
 java_binary {
     name: "content",
-    wrapper: "content",
+    wrapper: "content.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/content/content b/cmds/content/content.sh
similarity index 100%
rename from cmds/content/content
rename to cmds/content/content.sh
diff --git a/cmds/device_config/Android.bp b/cmds/device_config/Android.bp
index 69572d8..83b2730 100644
--- a/cmds/device_config/Android.bp
+++ b/cmds/device_config/Android.bp
@@ -14,5 +14,5 @@
 
 sh_binary {
     name: "device_config",
-    src: "device_config",
+    src: "device_config.sh",
 }
diff --git a/cmds/device_config/device_config b/cmds/device_config/device_config.sh
similarity index 100%
rename from cmds/device_config/device_config
rename to cmds/device_config/device_config.sh
diff --git a/cmds/dpm/Android.bp b/cmds/dpm/Android.bp
index 6819d09..29bee49 100644
--- a/cmds/dpm/Android.bp
+++ b/cmds/dpm/Android.bp
@@ -20,5 +20,5 @@
 
 sh_binary {
     name: "dpm",
-    src: "dpm",
+    src: "dpm.sh",
 }
diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm.sh
similarity index 100%
rename from cmds/dpm/dpm
rename to cmds/dpm/dpm.sh
diff --git a/cmds/hid/Android.bp b/cmds/hid/Android.bp
index 295c71c..a6e2769 100644
--- a/cmds/hid/Android.bp
+++ b/cmds/hid/Android.bp
@@ -20,7 +20,7 @@
 
 java_binary {
     name: "hid",
-    wrapper: "hid",
+    wrapper: "hid.sh",
     srcs: ["**/*.java"],
     required: ["libhidcommand_jni"],
 }
diff --git a/cmds/hid/hid b/cmds/hid/hid.sh
similarity index 100%
rename from cmds/hid/hid
rename to cmds/hid/hid.sh
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 083bbf01..320e147 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -312,6 +312,8 @@
 Status Idmap2Service::releaseFabricatedOverlayIterator() {
   if (!frro_iter_.has_value()) {
     LOG(WARNING) << "no active ffro iterator to release";
+  } else {
+      frro_iter_ = std::nullopt;
   }
   return ok();
 }
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index 5b0ae92..8129d99 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -17,6 +17,7 @@
 #include "idmap2/CommandLineOptions.h"
 
 #include <algorithm>
+#include <cassert>
 #include <iomanip>
 #include <iostream>
 #include <memory>
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 6515d55..06650f6 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -17,6 +17,7 @@
 #include "idmap2/Idmap.h"
 
 #include <algorithm>
+#include <cassert>
 #include <iostream>
 #include <iterator>
 #include <limits>
diff --git a/cmds/ime/Android.bp b/cmds/ime/Android.bp
index 6dd3ba1..5f54ffa 100644
--- a/cmds/ime/Android.bp
+++ b/cmds/ime/Android.bp
@@ -20,5 +20,5 @@
 
 sh_binary {
     name: "ime",
-    src: "ime",
+    src: "ime.sh",
 }
diff --git a/cmds/ime/ime b/cmds/ime/ime.sh
similarity index 100%
rename from cmds/ime/ime
rename to cmds/ime/ime.sh
diff --git a/cmds/input/Android.bp b/cmds/input/Android.bp
index 2e301769..8f44f3e 100644
--- a/cmds/input/Android.bp
+++ b/cmds/input/Android.bp
@@ -20,5 +20,5 @@
 
 sh_binary {
     name: "input",
-    src: "input",
+    src: "input.sh",
 }
diff --git a/cmds/input/input b/cmds/input/input.sh
similarity index 100%
rename from cmds/input/input
rename to cmds/input/input.sh
diff --git a/cmds/locksettings/Android.bp b/cmds/locksettings/Android.bp
index 3869c8f..5ee5824 100644
--- a/cmds/locksettings/Android.bp
+++ b/cmds/locksettings/Android.bp
@@ -23,6 +23,6 @@
 
 java_binary {
     name: "locksettings",
-    wrapper: "locksettings",
+    wrapper: "locksettings.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings.sh
similarity index 100%
rename from cmds/locksettings/locksettings
rename to cmds/locksettings/locksettings.sh
diff --git a/cmds/pm/Android.bp b/cmds/pm/Android.bp
index 847dbab..0e61a9e 100644
--- a/cmds/pm/Android.bp
+++ b/cmds/pm/Android.bp
@@ -20,5 +20,5 @@
 
 sh_binary {
     name: "pm",
-    src: "pm",
+    src: "pm.sh",
 }
diff --git a/cmds/pm/pm b/cmds/pm/pm.sh
similarity index 100%
rename from cmds/pm/pm
rename to cmds/pm/pm.sh
diff --git a/cmds/requestsync/Android.bp b/cmds/requestsync/Android.bp
index 57e8dd3..8718f79 100644
--- a/cmds/requestsync/Android.bp
+++ b/cmds/requestsync/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "requestsync",
-    wrapper: "requestsync",
+    wrapper: "requestsync.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/requestsync/requestsync b/cmds/requestsync/requestsync.sh
similarity index 100%
rename from cmds/requestsync/requestsync
rename to cmds/requestsync/requestsync.sh
diff --git a/cmds/screencap/OWNERS b/cmds/screencap/OWNERS
new file mode 100644
index 0000000..89f1177
--- /dev/null
+++ b/cmds/screencap/OWNERS
@@ -0,0 +1,2 @@
+include /graphics/java/android/graphics/OWNERS
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/cmds/settings/Android.bp b/cmds/settings/Android.bp
index cc73006..8180fd6 100644
--- a/cmds/settings/Android.bp
+++ b/cmds/settings/Android.bp
@@ -14,5 +14,5 @@
 
 sh_binary {
     name: "settings",
-    src: "settings",
+    src: "settings.sh",
 }
diff --git a/cmds/settings/settings b/cmds/settings/settings.sh
similarity index 100%
rename from cmds/settings/settings
rename to cmds/settings/settings.sh
diff --git a/cmds/sm/Android.bp b/cmds/sm/Android.bp
index ecfacae..403022a 100644
--- a/cmds/sm/Android.bp
+++ b/cmds/sm/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "sm",
-    wrapper: "sm",
+    wrapper: "sm.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/sm/sm b/cmds/sm/sm.sh
similarity index 100%
rename from cmds/sm/sm
rename to cmds/sm/sm.sh
diff --git a/cmds/svc/Android.bp b/cmds/svc/Android.bp
index 41a3ebd..a246087 100644
--- a/cmds/svc/Android.bp
+++ b/cmds/svc/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "svc",
-    wrapper: "svc",
+    wrapper: "svc.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/svc/svc b/cmds/svc/svc.sh
similarity index 100%
rename from cmds/svc/svc
rename to cmds/svc/svc.sh
diff --git a/cmds/telecom/Android.bp b/cmds/telecom/Android.bp
index 4da79c5..be02710 100644
--- a/cmds/telecom/Android.bp
+++ b/cmds/telecom/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "telecom",
-    wrapper: "telecom",
+    wrapper: "telecom.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/telecom/telecom b/cmds/telecom/telecom.sh
similarity index 100%
rename from cmds/telecom/telecom
rename to cmds/telecom/telecom.sh
diff --git a/cmds/uiautomator/cmds/uiautomator/Android.bp b/cmds/uiautomator/cmds/uiautomator/Android.bp
index 56e2e70..5132386 100644
--- a/cmds/uiautomator/cmds/uiautomator/Android.bp
+++ b/cmds/uiautomator/cmds/uiautomator/Android.bp
@@ -25,7 +25,7 @@
 
 java_binary {
     name: "uiautomator",
-    wrapper: "uiautomator",
+    wrapper: "uiautomator.sh",
     srcs: ["src/**/*.java"],
     static_libs: ["uiautomator.core"],
 }
diff --git a/cmds/uiautomator/cmds/uiautomator/uiautomator b/cmds/uiautomator/cmds/uiautomator/uiautomator.sh
similarity index 100%
rename from cmds/uiautomator/cmds/uiautomator/uiautomator
rename to cmds/uiautomator/cmds/uiautomator/uiautomator.sh
diff --git a/cmds/uinput/Android.bp b/cmds/uinput/Android.bp
index 260cfc7..4b08d96 100644
--- a/cmds/uinput/Android.bp
+++ b/cmds/uinput/Android.bp
@@ -20,9 +20,10 @@
 
 java_binary {
     name: "uinput",
-    wrapper: "uinput",
-    srcs: ["**/*.java",
-           ":uinputcommand_aidl"
+    wrapper: "uinput.sh",
+    srcs: [
+        "**/*.java",
+        ":uinputcommand_aidl",
     ],
     required: ["libuinputcommand_jni"],
 }
diff --git a/cmds/uinput/uinput b/cmds/uinput/uinput.sh
similarity index 100%
rename from cmds/uinput/uinput
rename to cmds/uinput/uinput.sh
diff --git a/cmds/vr/Android.bp b/cmds/vr/Android.bp
index 8936491..61795b4c 100644
--- a/cmds/vr/Android.bp
+++ b/cmds/vr/Android.bp
@@ -20,6 +20,6 @@
 
 java_binary {
     name: "vr",
-    wrapper: "vr",
+    wrapper: "vr.sh",
     srcs: ["**/*.java"],
 }
diff --git a/cmds/vr/vr b/cmds/vr/vr.sh
similarity index 100%
rename from cmds/vr/vr
rename to cmds/vr/vr.sh
diff --git a/cmds/wm/Android.bp b/cmds/wm/Android.bp
index cf6b019..4d00f17 100644
--- a/cmds/wm/Android.bp
+++ b/cmds/wm/Android.bp
@@ -20,5 +20,5 @@
 
 sh_binary {
     name: "wm",
-    src: "wm",
+    src: "wm.sh",
 }
diff --git a/cmds/wm/wm b/cmds/wm/wm.sh
similarity index 100%
rename from cmds/wm/wm
rename to cmds/wm/wm.sh
diff --git a/core/api/current.txt b/core/api/current.txt
index 2411a4e..4d25ad7 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
@@ -32172,6 +32177,7 @@
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectCustomSlowCalls();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectDiskReads();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectDiskWrites();
+    method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectExplicitGc();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectNetwork();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectResourceMismatches();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectUnbufferedIo();
@@ -32186,6 +32192,7 @@
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitCustomSlowCalls();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitDiskReads();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitDiskWrites();
+    method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitExplicitGc();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitNetwork();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitResourceMismatches();
     method @NonNull public android.os.StrictMode.ThreadPolicy.Builder permitUnbufferedIo();
@@ -32767,6 +32774,9 @@
   public final class DiskWriteViolation extends android.os.strictmode.Violation {
   }
 
+  public final class ExplicitGcViolation extends android.os.strictmode.Violation {
+  }
+
   public final class FileUriExposedViolation extends android.os.strictmode.Violation {
   }
 
@@ -41360,6 +41370,7 @@
     field public static final String KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING = "call_composer_picture_server_url_string";
     field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array";
     field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string";
+    field public static final String KEY_CAPABILITIES_EXEMPT_FROM_SINGLE_DC_CHECK_INT_ARRAY = "capabilities_exempt_from_single_dc_check_int_array";
     field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool";
     field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool";
@@ -42349,6 +42360,7 @@
     field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
     field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
     field public static final int IWLAN_AUTHORIZATION_REJECTED = 9003; // 0x232b
+    field public static final int IWLAN_CONGESTION = 15500; // 0x3c8c
     field public static final int IWLAN_DNS_RESOLUTION_NAME_FAILURE = 16388; // 0x4004
     field public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 16389; // 0x4005
     field public static final int IWLAN_IKEV2_AUTH_FAILURE = 16385; // 0x4001
@@ -48655,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
@@ -49450,6 +49465,7 @@
   public class Surface implements android.os.Parcelable {
     ctor public Surface(@NonNull android.view.SurfaceControl);
     ctor public Surface(android.graphics.SurfaceTexture);
+    method public void clearFrameRate();
     method public int describeContents();
     method public boolean isValid();
     method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException;
@@ -49507,6 +49523,7 @@
     ctor public SurfaceControl.Transaction();
     method @NonNull public android.view.SurfaceControl.Transaction addTransactionCommittedListener(@NonNull java.util.concurrent.Executor, @NonNull android.view.SurfaceControl.TransactionCommittedListener);
     method public void apply();
+    method @NonNull public android.view.SurfaceControl.Transaction clearFrameRate(@NonNull android.view.SurfaceControl);
     method public void close();
     method public int describeContents();
     method @NonNull public android.view.SurfaceControl.Transaction merge(@NonNull android.view.SurfaceControl.Transaction);
@@ -51832,6 +51849,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
@@ -52017,7 +52035,6 @@
     method public boolean isTextEntryKey();
     method public boolean isTextSelectable();
     method public boolean isVisibleToUser();
-    method public void makeQueryableFromAppProcess(@NonNull android.view.View);
     method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
     method @Deprecated public static android.view.accessibility.AccessibilityNodeInfo obtain();
@@ -52070,6 +52087,7 @@
     method public void setParent(android.view.View);
     method public void setParent(android.view.View, int);
     method public void setPassword(boolean);
+    method public void setQueryFromAppProcessEnabled(@NonNull android.view.View, boolean);
     method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
     method public void setScreenReaderFocusable(boolean);
     method public void setScrollable(boolean);
@@ -53005,6 +53023,7 @@
     method public android.graphics.Matrix getMatrix();
     method public int getSelectionEnd();
     method public int getSelectionStart();
+    method @NonNull public java.util.List<android.graphics.RectF> getVisibleLineBounds();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.CursorAnchorInfo> CREATOR;
     field public static final int FLAG_HAS_INVISIBLE_REGION = 2; // 0x2
@@ -53015,7 +53034,9 @@
   public static final class CursorAnchorInfo.Builder {
     ctor public CursorAnchorInfo.Builder();
     method public android.view.inputmethod.CursorAnchorInfo.Builder addCharacterBounds(int, float, float, float, float, int);
+    method @NonNull public android.view.inputmethod.CursorAnchorInfo.Builder addVisibleLineBounds(float, float, float, float);
     method public android.view.inputmethod.CursorAnchorInfo build();
+    method @NonNull public android.view.inputmethod.CursorAnchorInfo.Builder clearVisibleLineBounds();
     method public void reset();
     method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, CharSequence);
     method @NonNull public android.view.inputmethod.CursorAnchorInfo.Builder setEditorBoundsInfo(@Nullable android.view.inputmethod.EditorBoundsInfo);
@@ -53140,7 +53161,9 @@
     method @Nullable public String getFallbackText();
     field public static final int GESTURE_TYPE_DELETE = 4; // 0x4
     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 GRANULARITY_CHARACTER = 2; // 0x2
     field public static final int GRANULARITY_WORD = 1; // 0x1
@@ -53253,6 +53276,7 @@
     field public static final int CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS = 8; // 0x8
     field public static final int CURSOR_UPDATE_FILTER_EDITOR_BOUNDS = 4; // 0x4
     field public static final int CURSOR_UPDATE_FILTER_INSERTION_MARKER = 16; // 0x10
+    field public static final int CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS = 32; // 0x20
     field public static final int CURSOR_UPDATE_IMMEDIATE = 1; // 0x1
     field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
     field public static final int GET_EXTRACTED_TEXT_MONITOR = 1; // 0x1
@@ -53480,6 +53504,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();
@@ -55979,9 +56032,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 ef8ae70..f09244a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -573,6 +573,7 @@
     field public static final String OPSTR_READ_MEDIA_AUDIO = "android:read_media_audio";
     field public static final String OPSTR_READ_MEDIA_IMAGES = "android:read_media_images";
     field public static final String OPSTR_READ_MEDIA_VIDEO = "android:read_media_video";
+    field public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO = "android:receive_ambient_trigger_audio";
     field public static final String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
     field public static final String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
     field public static final String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
@@ -6134,6 +6135,11 @@
     field public static final int ROLE_OUTPUT = 2; // 0x2
   }
 
+  public class AudioDeviceVolumeManager {
+    ctor public AudioDeviceVolumeManager(@NonNull android.content.Context);
+    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolume(@NonNull android.media.VolumeInfo, @NonNull android.media.AudioDeviceAttributes);
+  }
+
   public final class AudioFocusInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public android.media.AudioAttributes getAttributes();
@@ -6453,6 +6459,33 @@
     method public void onSpatializerOutputChanged(@NonNull android.media.Spatializer, @IntRange(from=0) int);
   }
 
+  public final class VolumeInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public static android.media.VolumeInfo getDefaultVolumeInfo();
+    method public int getMaxVolumeIndex();
+    method public int getMinVolumeIndex();
+    method public int getStreamType();
+    method @Nullable public android.media.audiopolicy.AudioVolumeGroup getVolumeGroup();
+    method public int getVolumeIndex();
+    method public boolean hasStreamType();
+    method public boolean hasVolumeGroup();
+    method public boolean isMuted();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.VolumeInfo> CREATOR;
+    field public static final int INDEX_NOT_SET = -100; // 0xffffff9c
+  }
+
+  public static final class VolumeInfo.Builder {
+    ctor public VolumeInfo.Builder(int);
+    ctor public VolumeInfo.Builder(@NonNull android.media.audiopolicy.AudioVolumeGroup);
+    ctor public VolumeInfo.Builder(@NonNull android.media.VolumeInfo);
+    method @NonNull public android.media.VolumeInfo build();
+    method @NonNull public android.media.VolumeInfo.Builder setMaxVolumeIndex(int);
+    method @NonNull public android.media.VolumeInfo.Builder setMinVolumeIndex(int);
+    method @NonNull public android.media.VolumeInfo.Builder setMuted(boolean);
+    method @NonNull public android.media.VolumeInfo.Builder setVolumeIndex(int);
+  }
+
 }
 
 package android.media.audiofx {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index bb6cc45..deb5aca 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -288,7 +288,8 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setActiveDream(@Nullable android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setDreamOverlay(@Nullable android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setScreensaverEnabled(boolean);
-    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream(@NonNull android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setSystemDreamComponent(@Nullable android.content.ComponentName);
+    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream();
     method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
   }
 
@@ -522,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);
@@ -793,6 +794,7 @@
     field public static final long FORCE_RESIZE_APP = 174042936L; // 0xa5faf38L
     field public static final long NEVER_SANDBOX_DISPLAY_APIS = 184838306L; // 0xb0468a2L
     field public static final long OVERRIDE_MIN_ASPECT_RATIO = 174042980L; // 0xa5faf64L
+    field public static final long OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN = 218959984L; // 0xd0d1070L
     field public static final long OVERRIDE_MIN_ASPECT_RATIO_LARGE = 180326787L; // 0xabf9183L
     field public static final float OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE = 1.7777778f;
     field public static final long OVERRIDE_MIN_ASPECT_RATIO_MEDIUM = 180326845L; // 0xabf91bdL
@@ -1826,10 +1828,6 @@
     method public static void setViolationLogger(android.os.StrictMode.ViolationLogger);
   }
 
-  public static final class StrictMode.ThreadPolicy.Builder {
-    method @NonNull public android.os.StrictMode.ThreadPolicy.Builder detectExplicitGc();
-  }
-
   public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
     ctor public StrictMode.ViolationInfo(android.os.Parcel);
     ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
@@ -2038,13 +2036,6 @@
 
 }
 
-package android.os.strictmode {
-
-  public final class ExplicitGcViolation extends android.os.strictmode.Violation {
-  }
-
-}
-
 package android.os.vibrator {
 
   public final class PrebakedSegment extends android.os.vibrator.VibrationEffectSegment {
@@ -2169,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
   }
@@ -2392,6 +2388,16 @@
     method public final boolean shouldShowComplications();
   }
 
+  public class DreamService extends android.app.Service implements android.view.Window.Callback {
+    method @Nullable public static android.service.dreams.DreamService.DreamMetadata getDreamMetadata(@NonNull android.content.Context, @Nullable android.content.pm.ServiceInfo);
+  }
+
+  public static final class DreamService.DreamMetadata {
+    field @Nullable public final android.graphics.drawable.Drawable previewImage;
+    field @Nullable public final android.content.ComponentName settingsActivity;
+    field @NonNull public final boolean showComplications;
+  }
+
 }
 
 package android.service.notification {
@@ -2848,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 = 307; // 0x133
   }
 
   public final class KeyboardShortcutGroup implements android.os.Parcelable {
@@ -3342,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);
@@ -3386,11 +3431,13 @@
     method @NonNull public android.window.WindowContainerTransaction createTaskFragment(@NonNull android.window.TaskFragmentCreationParams);
     method @NonNull public android.window.WindowContainerTransaction deleteTaskFragment(@NonNull android.window.WindowContainerToken);
     method public int describeContents();
+    method @NonNull public android.window.WindowContainerTransaction removeTask(@NonNull android.window.WindowContainerToken);
     method @NonNull public android.window.WindowContainerTransaction reorder(@NonNull android.window.WindowContainerToken, boolean);
     method @NonNull public android.window.WindowContainerTransaction reparent(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, boolean);
     method @NonNull public android.window.WindowContainerTransaction reparentActivityToTaskFragment(@NonNull android.os.IBinder, @NonNull android.os.IBinder);
     method @NonNull public android.window.WindowContainerTransaction reparentChildren(@NonNull android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken);
     method @NonNull public android.window.WindowContainerTransaction reparentTasks(@Nullable android.window.WindowContainerToken, @Nullable android.window.WindowContainerToken, @Nullable int[], @Nullable int[], boolean);
+    method @NonNull public android.window.WindowContainerTransaction requestFocusOnTaskFragment(@NonNull android.os.IBinder);
     method @NonNull public android.window.WindowContainerTransaction scheduleFinishEnterPip(@NonNull android.window.WindowContainerToken, @NonNull android.graphics.Rect);
     method @NonNull public android.window.WindowContainerTransaction setActivityWindowingMode(@NonNull android.window.WindowContainerToken, int);
     method @NonNull public android.window.WindowContainerTransaction setAdjacentRoots(@NonNull android.window.WindowContainerToken, @NonNull android.window.WindowContainerToken);
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 30dbec7..8f5457a 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3128,7 +3128,13 @@
         /**
          * All packages that have been loaded into the process.
          */
-        public String pkgList[];
+        public String[] pkgList;
+
+        /**
+         * Additional packages loaded into the process as dependency.
+         * @hide
+         */
+        public String[] pkgDeps;
 
         /**
          * Constant for {@link #flags}: this is an app that is unable to
@@ -3509,6 +3515,7 @@
             dest.writeInt(pid);
             dest.writeInt(uid);
             dest.writeStringArray(pkgList);
+            dest.writeStringArray(pkgDeps);
             dest.writeInt(this.flags);
             dest.writeInt(lastTrimLevel);
             dest.writeInt(importance);
@@ -3527,6 +3534,7 @@
             pid = source.readInt();
             uid = source.readInt();
             pkgList = source.readStringArray();
+            pkgDeps = source.readStringArray();
             flags = source.readInt();
             lastTrimLevel = source.readInt();
             importance = source.readInt();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index db76816..ee5d2b7 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -533,9 +533,8 @@
         // A reusable token for other purposes, e.g. content capture, translation. It shouldn't be
         // used without security checks
         public IBinder shareableActivityToken;
-        // The token of the initial TaskFragment that embedded this activity. Do not rely on it
-        // after creation because the activity could be reparented.
-        @Nullable public IBinder mInitialTaskFragmentToken;
+        // The token of the TaskFragment that embedded this activity.
+        @Nullable public IBinder mTaskFragmentToken;
         int ident;
         @UnsupportedAppUsage
         Intent intent;
@@ -619,7 +618,7 @@
                 List<ReferrerIntent> pendingNewIntents, ActivityOptions activityOptions,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
-                IBinder initialTaskFragmentToken) {
+                IBinder taskFragmentToken) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -638,7 +637,7 @@
             this.packageInfo = client.getPackageInfoNoCheck(activityInfo.applicationInfo);
             mActivityOptions = activityOptions;
             mLaunchedFromBubble = launchedFromBubble;
-            mInitialTaskFragmentToken = initialTaskFragmentToken;
+            mTaskFragmentToken = taskFragmentToken;
             init();
         }
 
@@ -1177,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;
@@ -1756,6 +1762,7 @@
             UpdateCompatibilityData ucd = new UpdateCompatibilityData();
             ucd.pkg = pkg;
             ucd.info = info;
+            updateCompatOverrideScale(info);
             sendMessage(H.UPDATE_PACKAGE_COMPATIBILITY_INFO, ucd);
         }
 
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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 2a5916d..bc59d60 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1812,6 +1812,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final String OPSTR_RECEIVE_AMBIENT_TRIGGER_AUDIO =
             "android:receive_ambient_trigger_audio";
 
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index c0aebee..7bfb1b5 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -48,6 +48,13 @@
     private String mPkg;
 
     /**
+     * The maximum string length for any string contained in this automatic zen rule. This pertains
+     * both to fields in the rule itself (such as its name) and items with sub-fields.
+     * @hide
+     */
+    public static final int MAX_STRING_LENGTH = 1000;
+
+    /**
      * Creates an automatic zen rule.
      *
      * @param name The name of the rule.
@@ -93,10 +100,10 @@
     public AutomaticZenRule(@NonNull String name, @Nullable ComponentName owner,
             @Nullable ComponentName configurationActivity, @NonNull Uri conditionId,
             @Nullable ZenPolicy policy, int interruptionFilter, boolean enabled) {
-        this.name = name;
-        this.owner = owner;
-        this.configurationActivity = configurationActivity;
-        this.conditionId = conditionId;
+        this.name = getTrimmedString(name);
+        this.owner = getTrimmedComponentName(owner);
+        this.configurationActivity = getTrimmedComponentName(configurationActivity);
+        this.conditionId = getTrimmedUri(conditionId);
         this.interruptionFilter = interruptionFilter;
         this.enabled = enabled;
         this.mZenPolicy = policy;
@@ -115,12 +122,14 @@
     public AutomaticZenRule(Parcel source) {
         enabled = source.readInt() == ENABLED;
         if (source.readInt() == ENABLED) {
-            name = source.readString();
+            name = getTrimmedString(source.readString());
         }
         interruptionFilter = source.readInt();
-        conditionId = source.readParcelable(null, android.net.Uri.class);
-        owner = source.readParcelable(null, android.content.ComponentName.class);
-        configurationActivity = source.readParcelable(null, android.content.ComponentName.class);
+        conditionId = getTrimmedUri(source.readParcelable(null, android.net.Uri.class));
+        owner = getTrimmedComponentName(
+                source.readParcelable(null, android.content.ComponentName.class));
+        configurationActivity = getTrimmedComponentName(
+                source.readParcelable(null, android.content.ComponentName.class));
         creationTime = source.readLong();
         mZenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
         mModified = source.readInt() == ENABLED;
@@ -196,7 +205,7 @@
      * Sets the representation of the state that causes this rule to become active.
      */
     public void setConditionId(Uri conditionId) {
-        this.conditionId = conditionId;
+        this.conditionId = getTrimmedUri(conditionId);
     }
 
     /**
@@ -211,7 +220,7 @@
      * Sets the name of this rule.
      */
     public void setName(String name) {
-        this.name = name;
+        this.name = getTrimmedString(name);
     }
 
     /**
@@ -243,7 +252,7 @@
      * that are not backed by {@link android.service.notification.ConditionProviderService}.
      */
     public void setConfigurationActivity(@Nullable ComponentName componentName) {
-        this.configurationActivity = componentName;
+        this.configurationActivity = getTrimmedComponentName(componentName);
     }
 
     /**
@@ -333,4 +342,35 @@
             return new AutomaticZenRule[size];
         }
     };
+
+    /**
+     * If the package or class name of the provided ComponentName are longer than MAX_STRING_LENGTH,
+     * return a trimmed version that truncates each of the package and class name at the max length.
+     */
+    private static ComponentName getTrimmedComponentName(ComponentName cn) {
+        if (cn == null) return null;
+        return new ComponentName(getTrimmedString(cn.getPackageName()),
+                getTrimmedString(cn.getClassName()));
+    }
+
+    /**
+     * 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/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4c7bc6d..80121b7 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1390,8 +1390,9 @@
                 if (scheduler == null) {
                     scheduler = mMainThread.getHandler();
                 }
-                rd = new LoadedApk.ReceiverDispatcher(
-                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+                        resultReceiver, getOuterContext(), scheduler, null, false)
+                                .getIIntentReceiver();
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1497,8 +1498,9 @@
                 if (scheduler == null) {
                     scheduler = mMainThread.getHandler();
                 }
-                rd = new LoadedApk.ReceiverDispatcher(resultReceiver, getOuterContext(),
-                        scheduler, null, false).getIIntentReceiver();
+                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+                        resultReceiver, getOuterContext(), scheduler, null, false)
+                                .getIIntentReceiver();
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1616,8 +1618,9 @@
                 if (scheduler == null) {
                     scheduler = mMainThread.getHandler();
                 }
-                rd = new LoadedApk.ReceiverDispatcher(
-                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+                        resultReceiver, getOuterContext(), scheduler, null, false)
+                                .getIIntentReceiver();
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1699,8 +1702,9 @@
                 if (scheduler == null) {
                     scheduler = mMainThread.getHandler();
                 }
-                rd = new LoadedApk.ReceiverDispatcher(
-                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
+                        resultReceiver, getOuterContext(), scheduler, null, false)
+                                .getIIntentReceiver();
             }
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
@@ -1802,7 +1806,7 @@
                 if (scheduler == null) {
                     scheduler = mMainThread.getHandler();
                 }
-                rd = new LoadedApk.ReceiverDispatcher(
+                rd = new LoadedApk.ReceiverDispatcher(mMainThread.getApplicationThread(),
                         receiver, context, scheduler, null, true).getIIntentReceiver();
             }
         }
diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java
index 00af1c02..7c8b0fd 100644
--- a/core/java/android/app/DreamManager.java
+++ b/core/java/android/app/DreamManager.java
@@ -18,7 +18,6 @@
 
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemService;
@@ -86,16 +85,23 @@
     }
 
     /**
-     * Starts dream service with name "name".
+     * Starts dreaming.
+     *
+     * The system dream component, if set by {@link DreamManager#setSystemDreamComponent}, will be
+     * started.
+     * Otherwise, starts the active dream set by {@link DreamManager#setActiveDream}.
      *
      * <p>This is only used for testing the dream service APIs.
      *
+     * @see DreamManager#setActiveDream(ComponentName)
+     * @see DreamManager#setSystemDreamComponent(ComponentName)
+     *
      * @hide
      */
     @TestApi
     @UserHandleAware
     @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
-    public void startDream(@NonNull ComponentName name) {
+    public void startDream() {
         try {
             mService.dream();
         } catch (RemoteException e) {
@@ -142,6 +148,25 @@
     }
 
     /**
+     * Sets or clears the system dream component.
+     *
+     * The system dream component, when set, will be shown instead of the user configured dream
+     * when the system starts dreaming (not dozing). If the system is dreaming at the time the
+     * system dream is set or cleared, it immediately switches dream.
+     *
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
+    public void setSystemDreamComponent(@Nullable ComponentName dreamComponent) {
+        try {
+            mService.setSystemDreamComponent(dreamComponent);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets the active dream on the device to be "dreamComponent".
      *
      * <p>This is only used for testing the dream service APIs.
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0849a6f..3620a60 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1598,8 +1598,8 @@
                 }
             }
             if (rd == null) {
-                rd = new ReceiverDispatcher(r, context, handler,
-                        instrumentation, registered);
+                rd = new ReceiverDispatcher(mActivityThread.getApplicationThread(), r, context,
+                        handler, instrumentation, registered);
                 if (registered) {
                     if (map == null) {
                         map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
@@ -1714,6 +1714,7 @@
             }
         }
 
+        final IApplicationThread mAppThread;
         final IIntentReceiver.Stub mIIntentReceiver;
         @UnsupportedAppUsage
         final BroadcastReceiver mReceiver;
@@ -1736,7 +1737,7 @@
                     boolean ordered, boolean sticky, int sendingUser) {
                 super(resultCode, resultData, resultExtras,
                         mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
-                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
+                        sticky, mAppThread.asBinder(), sendingUser, intent.getFlags());
                 mCurIntent = intent;
                 mOrdered = ordered;
             }
@@ -1811,13 +1812,14 @@
             }
         }
 
-        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
-                Handler activityThread, Instrumentation instrumentation,
+        ReceiverDispatcher(IApplicationThread appThread, BroadcastReceiver receiver,
+                Context context, Handler activityThread, Instrumentation instrumentation,
                 boolean registered) {
             if (activityThread == null) {
                 throw new NullPointerException("Handler must not be null");
             }
 
+            mAppThread = appThread;
             mIIntentReceiver = new InnerReceiver(this, !registered);
             mReceiver = receiver;
             mContext = context;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index b9ad595..7215987 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -753,7 +753,7 @@
 
     /**
      * Returns the vibration pattern for notifications posted to this channel. Will be ignored if
-     * vibration is not enabled ({@link #shouldVibrate()}.
+     * vibration is not enabled ({@link #shouldVibrate()}).
      */
     public long[] getVibrationPattern() {
         return mVibration;
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/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index ae0fc09..6d289726 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -165,7 +165,7 @@
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Disable2Flags {}
-    // LINT.ThenChange(frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt)
+    // LINT.ThenChange(frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt)
 
     /**
      * Default disable flags for setup
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 7014d69..a5a50d6 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -43,6 +43,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
@@ -1103,7 +1104,10 @@
         }
         try {
             boolean[] res = mInteractor.supportsCommands(mContext.getOpPackageName(), commands);
-            if (DEBUG) Log.d(TAG, "supportsCommands: cmds=" + commands + " res=" + res);
+            if (DEBUG) {
+                Log.d(TAG, "supportsCommands: cmds=" + Arrays.toString(commands) + " res="
+                        + Arrays.toString(res));
+            }
             return res;
         } catch (RemoteException e) {
             throw new RuntimeException("Voice interactor has died", e);
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 6866510..ab11d6a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,7 @@
 
 package android.app.admin;
 
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
 import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
@@ -7393,6 +7394,9 @@
      * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED}
      * broadcast when access to a key is granted.
      *
+     * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} throws an
+     * {@link IllegalArgumentException} if {@code alias} doesn't correspond to an existing key.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *        {@code null} if calling from a delegated certificate chooser.
      * @param alias The alias of the key to grant access to.
@@ -7459,6 +7463,9 @@
      * The grantee app will receive the {@link android.security.KeyChain#ACTION_KEY_ACCESS_CHANGED}
      * broadcast when access to a key is revoked.
      *
+     * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} throws an
+     * {@link IllegalArgumentException} if {@code alias} doesn't correspond to an existing key.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *        {@code null} if calling from a delegated certificate chooser.
      * @param alias The alias of the key to revoke access from.
@@ -7489,6 +7496,9 @@
      * pair for authentication to Wifi networks. The key can then be used in configurations passed
      * to {@link android.net.wifi.WifiManager#addNetwork}.
      *
+     * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} throws an
+     * {@link IllegalArgumentException} if {@code alias} doesn't correspond to an existing key.
+     *
      * @param alias The alias of the key pair.
      * @return {@code true} if the operation was set successfully, {@code false} otherwise.
      *
@@ -7512,6 +7522,9 @@
      * pair for authentication to Wifi networks. Configured networks using this key won't be able to
      * authenticate.
      *
+     * Starting from {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} throws an
+     * {@link IllegalArgumentException} if {@code alias} doesn't correspond to an existing key.
+     *
      * @param alias The alias of the key pair.
      * @return {@code true} if the operation was set successfully, {@code false} otherwise.
      *
@@ -8676,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.
@@ -8688,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();
@@ -8702,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.
      *
@@ -8711,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();
@@ -8958,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();
             }
@@ -9020,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();
             }
@@ -10802,14 +10809,19 @@
      */
     public Intent createAdminSupportIntent(@NonNull String restriction) {
         throwIfParentInstance("createAdminSupportIntent");
+        Intent result = null;
         if (mService != null) {
             try {
-                return mService.createAdminSupportIntent(restriction);
+                result = mService.createAdminSupportIntent(restriction);
+                if (result != null) {
+                    result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+                            mContext.getAttributionSource());
+                }
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
         }
-        return null;
+        return result;
     }
 
     /**
@@ -15411,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/admin/PreferentialNetworkServiceConfig.java b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
index 24b4f4b..63c9839 100644
--- a/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
+++ b/core/java/android/app/admin/PreferentialNetworkServiceConfig.java
@@ -203,17 +203,14 @@
         return mIsEnabled == that.mIsEnabled
                 && mAllowFallbackToDefaultConnection == that.mAllowFallbackToDefaultConnection
                 && mNetworkId == that.mNetworkId
-                && Objects.equals(mIncludedUids, that.mIncludedUids)
-                && Objects.equals(mExcludedUids, that.mExcludedUids);
+                && Arrays.equals(mIncludedUids, that.mIncludedUids)
+                && Arrays.equals(mExcludedUids, that.mExcludedUids);
     }
 
     @Override
     public int hashCode() {
-        return ((Objects.hashCode(mIsEnabled) * 17)
-                + (Objects.hashCode(mAllowFallbackToDefaultConnection) * 19)
-                + (Objects.hashCode(mIncludedUids) * 23)
-                + (Objects.hashCode(mExcludedUids) * 29)
-                + mNetworkId * 31);
+        return Objects.hash(mIsEnabled, mAllowFallbackToDefaultConnection,
+                Arrays.hashCode(mIncludedUids), Arrays.hashCode(mExcludedUids), mNetworkId);
     }
 
     /**
diff --git a/core/java/android/app/ambientcontext/AmbientContextCallback.java b/core/java/android/app/ambientcontext/AmbientContextCallback.java
new file mode 100644
index 0000000..9133d7f
--- /dev/null
+++ b/core/java/android/app/ambientcontext/AmbientContextCallback.java
@@ -0,0 +1,47 @@
+/*
+ * 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.app.ambientcontext;
+
+import android.annotation.NonNull;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Callback for listening to Ambient Context events and status changes. See {@link
+ * AmbientContextManager#registerObserver(AmbientContextEventRequest, AmbientContextCallback,
+ * Executor)}
+ *
+ * @hide
+ */
+public interface AmbientContextCallback {
+    /**
+     * Called when AmbientContextManager service detects events.
+     *
+     * @param events a list of detected events.
+     */
+    void onEvents(@NonNull List<AmbientContextEvent> events);
+
+    /**
+     * Called with a statusCode when
+     * {@link AmbientContextManager#registerObserver(AmbientContextEventRequest,
+     * Executor, AmbientContextCallback)} completes, to indicate if the registration is successful
+     *
+     * @param statusCode the status of the service.
+     */
+    void onRegistrationComplete(@NonNull @AmbientContextManager.StatusCode int statusCode);
+}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java
index 11e695ad..af48fde 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEvent.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java
@@ -59,11 +59,21 @@
      */
     public static final int EVENT_SNORE = 2;
 
+    /**
+     * 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;
+
     /** @hide */
     @IntDef(prefix = { "EVENT_" }, value = {
             EVENT_UNKNOWN,
             EVENT_COUGH,
             EVENT_SNORE,
+            EVENT_BACK_DOUBLE_TAP,
     }) public @interface EventCode {}
 
     /** The integer indicating an unknown level. */
@@ -150,7 +160,8 @@
     @IntDef(prefix = "EVENT_", value = {
         EVENT_UNKNOWN,
         EVENT_COUGH,
-        EVENT_SNORE
+        EVENT_SNORE,
+        EVENT_BACK_DOUBLE_TAP
     })
     @Retention(RetentionPolicy.SOURCE)
     @DataClass.Generated.Member
@@ -166,6 +177,8 @@
                     return "EVENT_COUGH";
             case EVENT_SNORE:
                     return "EVENT_SNORE";
+            case EVENT_BACK_DOUBLE_TAP:
+                    return "EVENT_BACK_DOUBLE_TAP";
             default: return Integer.toHexString(value);
         }
     }
@@ -478,10 +491,10 @@
     }
 
     @DataClass.Generated(
-            time = 1642040319323L,
+            time = 1659950304931L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java",
-            inputSignatures = "public static final  int EVENT_UNKNOWN\npublic static final  int EVENT_COUGH\npublic static final  int EVENT_SNORE\npublic static final  int LEVEL_UNKNOWN\npublic static final  int LEVEL_LOW\npublic static final  int LEVEL_MEDIUM_LOW\npublic static final  int LEVEL_MEDIUM\npublic static final  int LEVEL_MEDIUM_HIGH\npublic static final  int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate static  int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultDensityLevel()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\[email protected](genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+            inputSignatures = "public static final  int EVENT_UNKNOWN\npublic static final  int EVENT_COUGH\npublic static final  int EVENT_SNORE\npublic static final  int EVENT_BACK_DOUBLE_TAP\npublic static final  int LEVEL_UNKNOWN\npublic static final  int LEVEL_LOW\npublic static final  int LEVEL_MEDIUM_LOW\npublic static final  int LEVEL_MEDIUM\npublic static final  int LEVEL_MEDIUM_HIGH\npublic static final  int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate static  int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultDensityLevel()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\[email protected](genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/ambientcontext/AmbientContextManager.java b/core/java/android/app/ambientcontext/AmbientContextManager.java
index 308c5ed..9cb1a20 100644
--- a/core/java/android/app/ambientcontext/AmbientContextManager.java
+++ b/core/java/android/app/ambientcontext/AmbientContextManager.java
@@ -282,7 +282,7 @@
         Preconditions.checkArgument(!resultPendingIntent.isImmutable());
         try {
             RemoteCallback callback = new RemoteCallback(result -> {
-                int statusCode =  result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
+                int statusCode = result.getInt(STATUS_RESPONSE_BUNDLE_KEY);
                 final long identity = Binder.clearCallingIdentity();
                 try {
                     executor.execute(() -> statusConsumer.accept(statusCode));
@@ -297,6 +297,72 @@
     }
 
     /**
+     * Allows app to register as a {@link AmbientContextEvent} observer. Same as {@link
+     * #registerObserver(AmbientContextEventRequest, PendingIntent, Executor, Consumer)},
+     * but use {@link AmbientContextCallback} instead of {@link PendingIntent} as a callback on
+     * detected events.
+     * Registering another observer from the same package that has already been
+     * registered will override the previous observer. If the same app previously calls
+     * {@link #registerObserver(AmbientContextEventRequest, AmbientContextCallback, Executor)},
+     * and now calls
+     * {@link #registerObserver(AmbientContextEventRequest, PendingIntent, Executor, Consumer)},
+     * the previous observer will be replaced with the new observer with the PendingIntent callback.
+     * Or vice versa.
+     *
+     * When the registration completes, a status will be returned to client through
+     * {@link AmbientContextCallback#onRegistrationComplete(int)}.
+     * If the AmbientContextManager service is not enabled yet, or the underlying detection service
+     * is not running yet, {@link AmbientContextManager#STATUS_SERVICE_UNAVAILABLE} will be
+     * returned, and the detection won't be really started.
+     * If the underlying detection service feature is not enabled, or the requested event type is
+     * not enabled yet, {@link AmbientContextManager#STATUS_NOT_SUPPORTED} will be returned, and the
+     * detection won't be really started.
+     * If there is no user consent,  {@link AmbientContextManager#STATUS_ACCESS_DENIED} will be
+     * returned, and the detection won't be really started.
+     * Otherwise, it will try to start the detection. And if it starts successfully, it will return
+     * {@link AmbientContextManager#STATUS_SUCCESS}. If it fails to start the detection, then
+     * it will return {@link AmbientContextManager#STATUS_SERVICE_UNAVAILABLE}
+     * After registerObserver succeeds and when the service detects an event, the service will
+     * trigger {@link AmbientContextCallback#onEvents(List)}.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)
+    public void registerObserver(
+            @NonNull AmbientContextEventRequest request,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull AmbientContextCallback ambientContextCallback) {
+        try {
+            IAmbientContextObserver observer = new IAmbientContextObserver.Stub() {
+                @Override
+                public void onEvents(List<AmbientContextEvent> events) throws RemoteException {
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(() -> ambientContextCallback.onEvents(events));
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                }
+
+                @Override
+                public void onRegistrationComplete(int statusCode) throws RemoteException {
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        executor.execute(
+                                () -> ambientContextCallback.onRegistrationComplete(statusCode));
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                }
+            };
+
+            mService.registerObserverWithCallback(request, mContext.getPackageName(), observer);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Unregisters the requesting app as an {@code AmbientContextEvent} observer. Unregistering an
      * observer that was already unregistered or never registered will have no effect.
      */
diff --git a/core/java/android/app/ambientcontext/IAmbientContextManager.aidl b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
index 0d9ecfd..8f06e76 100644
--- a/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
+++ b/core/java/android/app/ambientcontext/IAmbientContextManager.aidl
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEventRequest;
+import android.app.ambientcontext.IAmbientContextObserver;
 import android.os.RemoteCallback;
 
 /**
@@ -29,6 +30,11 @@
     void registerObserver(in AmbientContextEventRequest request,
         in PendingIntent resultPendingIntent,
         in RemoteCallback statusCallback);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT)")
+    void registerObserverWithCallback(in AmbientContextEventRequest request,
+        String packageName,
+        in IAmbientContextObserver observer);
     void unregisterObserver(in String callingPackage);
     void queryServiceStatus(in int[] eventTypes, in String callingPackage,
         in RemoteCallback statusCallback);
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/core/java/android/app/ambientcontext/IAmbientContextObserver.aidl
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
copy to core/java/android/app/ambientcontext/IAmbientContextObserver.aidl
index a29c588..529e2fe 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
+++ b/core/java/android/app/ambientcontext/IAmbientContextObserver.aidl
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package android.app.ambientcontext;
+
+import android.app.ambientcontext.AmbientContextEvent;
 
 /**
- * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ * Callback interface of AmbientContextManager.
+ *
+ * @hide
  */
-interface ChipInfoCommon {
-    /**
-     * Returns the amount of time the given chip state should display on the screen before it times
-     * out and disappears.
-     */
-    fun getTimeoutMs(): Long
+oneway interface IAmbientContextObserver {
+  void onEvents(in List<AmbientContextEvent> events);
+  void onRegistrationComplete(in int statusCode);
 }
 
-const val DEFAULT_TIMEOUT_MILLIS = 10000L
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 e6091f0..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;
 
@@ -204,9 +204,10 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mNamePattern, mScanFilter, mRawDataFilter, mRawDataFilterMask,
-                mRenamePrefix, mRenameSuffix, mRenameBytesFrom, mRenameBytesLength,
-                mRenameNameFrom, mRenameNameLength, mRenameBytesReverseOrder);
+        return Objects.hash(mNamePattern, mScanFilter, Arrays.hashCode(mRawDataFilter),
+                Arrays.hashCode(mRawDataFilterMask), mRenamePrefix, mRenameSuffix,
+                mRenameBytesFrom, mRenameBytesLength, mRenameNameFrom, mRenameNameLength,
+                mRenameBytesReverseOrder);
     }
 
     @Override
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/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 3f2fa21..b0c6cbc 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -495,14 +495,9 @@
 
     @Override
     public int hashCode() {
-        int _hash = 1;
-        _hash = 31 * _hash + mAttributionSourceState.uid;
-        _hash = 31 * _hash + Objects.hashCode(mAttributionSourceState.packageName);
-        _hash = 31 * _hash + Objects.hashCode(mAttributionSourceState.attributionTag);
-        _hash = 31 * _hash + Objects.hashCode(mAttributionSourceState.token);
-        _hash = 31 * _hash + Objects.hashCode(mAttributionSourceState.renouncedPermissions);
-        _hash = 31 * _hash + Objects.hashCode(getNext());
-        return _hash;
+        return Objects.hash(mAttributionSourceState.uid, mAttributionSourceState.packageName,
+                mAttributionSourceState.attributionTag, mAttributionSourceState.token,
+                Arrays.hashCode(mAttributionSourceState.renouncedPermissions), getNext());
     }
 
     @Override
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 896fe91..43fa617 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3920,6 +3920,12 @@
      * that has been started.  This is sent as a foreground
      * broadcast, since it is part of a visible user interaction; be as quick
      * as possible when handling it.
+     *
+     * <p>
+     * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+     * received. For example, the user could have been removed, started or stopped already,
+     * regardless of which broadcast you receive. Because of that, receivers should always check
+     * the current state of the user.
      * @hide
      */
     public static final String ACTION_USER_STARTED =
@@ -3937,6 +3943,12 @@
      * {@link #ACTION_USER_STOPPING}.  It is <b>not</b> generally safe to use with
      * other user state broadcasts since those are foreground broadcasts so can
      * execute in a different order.
+     *
+     * <p>
+     * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+     * received. For example, the user could have been removed, started or stopped already,
+     * regardless of which broadcast you receive. Because of that, receivers should always check
+     * the current state of the user.
      * @hide
      */
     public static final String ACTION_USER_STARTING =
@@ -3955,6 +3967,11 @@
      * {@link #ACTION_USER_STARTING}.  It is <b>not</b> generally safe to use with
      * other user state broadcasts since those are foreground broadcasts so can
      * execute in a different order.
+     * <p>
+     * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+     * received. For example, the user could have been removed, started or stopped already,
+     * regardless of which broadcast you receive. Because of that, receivers should always check
+     * the current state of the user.
      * @hide
      */
     public static final String ACTION_USER_STOPPING =
@@ -3967,6 +3984,12 @@
      * specific package.  This is only sent to registered receivers, not manifest
      * receivers.  It is sent to all running users <em>except</em> the one that
      * has just been stopped (which is no longer running).
+     *
+     * <p>
+     * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+     * received. For example, the user could have been removed, started or stopped already,
+     * regardless of which broadcast you receive. Because of that, receivers should always check
+     * the current state of the user.
      * @hide
      */
     @TestApi
@@ -3999,6 +4022,12 @@
      * It is sent to all running users.
      * You must hold
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
+     *
+     * <p>
+     * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+     * received. For example, the user could have been removed, started or stopped already,
+     * regardless of which broadcast you receive. Because of that, receivers should always check
+     * the current state of the user.
      * @hide
      */
     @SystemApi
@@ -4009,6 +4038,12 @@
      * Broadcast Action: Sent when the credential-encrypted private storage has
      * become unlocked for the target user. This is only sent to registered
      * receivers, not manifest receivers.
+     *
+     * <p>
+     * <b>Note:</b> The user's actual state might have changed by the time the broadcast is
+     * received. For example, the user could have been removed, started or stopped already,
+     * regardless of which broadcast you receive. Because of that, receivers should always check
+     * the current state of the user.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_USER_UNLOCKED = "android.intent.action.USER_UNLOCKED";
@@ -7163,12 +7198,18 @@
      */
     private static final int LOCAL_FLAG_FROM_URI = 1 << 4;
 
+    /**
+     * Local flag indicating this instance was created by the system.
+     */
+    /** @hide */
+    public static final int LOCAL_FLAG_FROM_SYSTEM = 1 << 5;
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
 
     /** @hide */
-    @IntDef(flag = true, prefix = { "URI_" }, value = {
+    @IntDef(flag = true, prefix = {"URI_"}, value = {
             URI_ALLOW_UNSAFE,
             URI_ANDROID_APP_SCHEME,
             URI_INTENT_SCHEME,
@@ -10574,7 +10615,9 @@
         // delivered Intent then it would have been reported when that Intent left the sending
         // process.
         if ((src.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
-                && (src.mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+                && (src.mLocalFlags & (
+                        LOCAL_FLAG_FROM_PROTECTED_COMPONENT
+                                | LOCAL_FLAG_FROM_SYSTEM)) == 0) {
             mLocalFlags |= LOCAL_FLAG_UNFILTERED_EXTRAS;
         }
         return this;
@@ -11917,13 +11960,14 @@
         // Detect cases where we're about to launch a potentially unsafe intent
         if (StrictMode.vmUnsafeIntentLaunchEnabled()) {
             if ((mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0
-                    && (mLocalFlags & LOCAL_FLAG_FROM_PROTECTED_COMPONENT) == 0) {
+                    && (mLocalFlags
+                    & (LOCAL_FLAG_FROM_PROTECTED_COMPONENT | LOCAL_FLAG_FROM_SYSTEM)) == 0) {
                 StrictMode.onUnsafeIntentLaunch(this);
             } else if ((mLocalFlags & LOCAL_FLAG_UNFILTERED_EXTRAS) != 0) {
                 StrictMode.onUnsafeIntentLaunch(this);
             } else if ((mLocalFlags & LOCAL_FLAG_FROM_URI) != 0
                     && !(mCategories != null && mCategories.contains(CATEGORY_BROWSABLE)
-                        && mComponent == null)) {
+                    && mComponent == null)) {
                 // Since the docs for #URI_ALLOW_UNSAFE recommend setting the category to browsable
                 // for an implicit Intent parsed from a URI a violation should be reported if these
                 // conditions are not met.
@@ -11936,6 +11980,17 @@
      * @hide
      */
     public void prepareToEnterProcess(boolean fromProtectedComponent, AttributionSource source) {
+        if (fromProtectedComponent) {
+            prepareToEnterProcess(LOCAL_FLAG_FROM_PROTECTED_COMPONENT, source);
+        } else {
+            prepareToEnterProcess(0, source);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void prepareToEnterProcess(int localFlags, AttributionSource source) {
         // We just entered destination process, so we should be able to read all
         // parcelables inside.
         setDefusable(true);
@@ -11943,13 +11998,15 @@
         if (mSelector != null) {
             // We can't recursively claim that this data is from a protected
             // component, since it may have been filled in by a malicious app
-            mSelector.prepareToEnterProcess(false, source);
+            mSelector.prepareToEnterProcess(0, source);
         }
         if (mClipData != null) {
             mClipData.prepareToEnterProcess(source);
         }
         if (mOriginalIntent != null) {
-            mOriginalIntent.prepareToEnterProcess(false, source);
+            // We can't recursively claim that this data is from a protected
+            // component, since it may have been filled in by a malicious app
+            mOriginalIntent.prepareToEnterProcess(0, source);
         }
 
         if (mContentUserHint != UserHandle.USER_CURRENT) {
@@ -11959,9 +12016,7 @@
             }
         }
 
-        if (fromProtectedComponent) {
-            mLocalFlags |= LOCAL_FLAG_FROM_PROTECTED_COMPONENT;
-        }
+        mLocalFlags |= localFlags;
 
         // Special attribution fix-up logic for any BluetoothDevice extras
         // passed via Bluetooth intents
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 885eb70..ffd80ea 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
+
 import android.annotation.SystemService;
 import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
@@ -487,14 +489,19 @@
     }
 
     public Intent createLocalApprovalIntent() {
+        Intent result = null;
         try {
             if (mService != null) {
-                return mService.createLocalApprovalIntent();
+                result = mService.createLocalApprovalIntent();
+                if (result != null) {
+                    result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+                            mContext.getAttributionSource());
+                }
             }
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
-        return null;
+        return result;
     }
 
     /**
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index e92be7c..26c947b 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1120,6 +1120,17 @@
     public static final long OVERRIDE_MIN_ASPECT_RATIO_TO_ALIGN_WITH_SPLIT_SCREEN = 208648326L;
 
     /**
+     * Overrides the min aspect ratio restriction in portrait fullscreen in order to use all
+     * available screen space.
+     * @hide
+     */
+    @ChangeId
+    @Disabled
+    @Overridable
+    @TestApi
+    public static final long OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN = 218959984L;
+
+    /**
      * Compares activity window layout min width/height with require space for multi window to
      * determine if it can be put into multi window mode.
      */
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index f780f81..f8c4974 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -1723,7 +1723,8 @@
         public void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing)
                 throws RemoteException {
             if (DEBUG) {
-                Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames);
+                Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + ","
+                        + Arrays.toString(packageNames));
             }
             synchronized (LauncherApps.this) {
                 for (CallbackMessageHandler callback : mCallbacks) {
@@ -1736,7 +1737,8 @@
         public void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing)
                 throws RemoteException {
             if (DEBUG) {
-                Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames);
+                Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + ","
+                        + Arrays.toString(packageNames));
             }
             synchronized (LauncherApps.this) {
                 for (CallbackMessageHandler callback : mCallbacks) {
@@ -1750,7 +1752,8 @@
                 Bundle launcherExtras)
                 throws RemoteException {
             if (DEBUG) {
-                Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + "," + packageNames);
+                Log.d(TAG, "onPackagesSuspended " + user.getIdentifier() + ","
+                        + Arrays.toString(packageNames));
             }
             synchronized (LauncherApps.this) {
                 for (CallbackMessageHandler callback : mCallbacks) {
@@ -1763,7 +1766,8 @@
         public void onPackagesUnsuspended(UserHandle user, String[] packageNames)
                 throws RemoteException {
             if (DEBUG) {
-                Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + "," + packageNames);
+                Log.d(TAG, "onPackagesUnsuspended " + user.getIdentifier() + ","
+                        + Arrays.toString(packageNames));
             }
             synchronized (LauncherApps.this) {
                 for (CallbackMessageHandler callback : mCallbacks) {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 52774e3..1f83d75 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -53,6 +53,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -2617,7 +2618,7 @@
         addIndentOrComma(sb, indent);
 
         sb.append("persons=");
-        sb.append(mPersons);
+        sb.append(Arrays.toString(mPersons));
 
         addIndentOrComma(sb, indent);
 
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 70b90e6..e48a02a 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -15,6 +15,8 @@
  */
 package android.content.pm;
 
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
+
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -628,7 +630,12 @@
         try {
             mService.createShortcutResultIntent(mContext.getPackageName(),
                     shortcut, injectMyUserId(), ret);
-            return getFutureOrThrow(ret);
+            Intent result = getFutureOrThrow(ret);
+            if (result != null) {
+                result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+                        mContext.getAttributionSource());
+            }
+            return result;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
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/content/res/GradientColor.java b/core/java/android/content/res/GradientColor.java
index 35ad503..7bc551d 100644
--- a/core/java/android/content/res/GradientColor.java
+++ b/core/java/android/content/res/GradientColor.java
@@ -22,13 +22,6 @@
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.Resources.Theme;
-
-import com.android.internal.R;
-import com.android.internal.util.GrowingArrayUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.graphics.LinearGradient;
 import android.graphics.RadialGradient;
 import android.graphics.Shader;
@@ -38,9 +31,16 @@
 import android.util.Log;
 import android.util.Xml;
 
+import com.android.internal.R;
+import com.android.internal.util.GrowingArrayUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
 
 /**
  * Lets you define a gradient color, which is used inside
@@ -466,7 +466,7 @@
         }
         if (tempColors.length < 2) {
             Log.w(TAG, "<gradient> tag requires 2 color values specified!" + tempColors.length
-                    + " " + tempColors);
+                    + " " + Arrays.toString(tempColors));
         }
 
         if (mGradientType == GradientDrawable.LINEAR_GRADIENT) {
diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl
new file mode 100644
index 0000000..a281cd5
--- /dev/null
+++ b/core/java/android/credentials/ICredentialManager.aidl
@@ -0,0 +1,10 @@
+package android.credentials;
+
+/**
+ * Mediator between apps and credential manager service implementations.
+ *
+ * {@hide}
+ */
+oneway interface ICredentialManager {
+    void getCredential();
+}
\ No newline at end of file
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/HardwareBuffer.aidl b/core/java/android/hardware/HardwareBuffer.aidl
index 5bdd966..1333f0d 100644
--- a/core/java/android/hardware/HardwareBuffer.aidl
+++ b/core/java/android/hardware/HardwareBuffer.aidl
@@ -16,4 +16,4 @@
 
 package android.hardware;
 
-parcelable HardwareBuffer;
+@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable HardwareBuffer ndk_header "android/hardware_buffer_aidl.h";
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/IBiometricContextListener.aidl b/core/java/android/hardware/biometrics/IBiometricContextListener.aidl
index 55cab52..2e8e763 100644
--- a/core/java/android/hardware/biometrics/IBiometricContextListener.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricContextListener.aidl
@@ -23,5 +23,8 @@
  * @hide
  */
 oneway interface IBiometricContextListener {
-    void onDozeChanged(boolean isDozing);
+    // Called when doze or awake (screen on) status changes.
+    // These may be called while the device is still transitioning to the new state
+    // (i.e. about to become awake or enter doze)
+    void onDozeChanged(boolean isDozing, boolean isAwake);
 }
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index d6d3a97..dff2f7e 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1204,6 +1204,20 @@
          * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after
          * {@link #onCameraAvailable}.</p>
          *
+         * <p>Limitation: Opening a logical camera disables the {@link #onPhysicalCameraAvailable}
+         * and {@link #onPhysicalCameraUnavailable} callbacks for its physical cameras. For example,
+         * if app A opens the camera device:</p>
+         *
+         * <ul>
+         *
+         * <li>All apps subscribing to ActivityCallback get {@link #onCameraUnavailable}.</li>
+         *
+         * <li>No app (including app A) subscribing to ActivityCallback gets
+         * {@link #onPhysicalCameraAvailable} or {@link #onPhysicalCameraUnavailable}, because
+         * the logical camera is unavailable (some app is using it).</li>
+         *
+         * </ul>
+         *
          * <p>The default implementation of this method does nothing.</p>
          *
          * @param cameraId The unique identifier of the logical multi-camera.
@@ -1221,11 +1235,24 @@
          * A previously-available physical camera has become unavailable for use.
          *
          * <p>By default, all of the physical cameras of a logical multi-camera are
-         * available, so {@link #onPhysicalCameraAvailable} is not called for any of the physical
-         * cameras of a logical multi-camera, when {@link #onCameraAvailable} for the logical
-         * multi-camera is invoked. If some specific physical cameras are unavailable
-         * to begin with, {@link #onPhysicalCameraUnavailable} may be invoked after
-         * {@link #onCameraAvailable}.</p>
+         * unavailable if the logical camera itself is unavailable.
+         * No availability callbacks will be called for any of the physical
+         * cameras of its parent logical multi-camera, when {@link #onCameraUnavailable} for
+         * the logical multi-camera is invoked.</p>
+         *
+         * <p>Limitation: Opening a logical camera disables the {@link #onPhysicalCameraAvailable}
+         * and {@link #onPhysicalCameraUnavailable} callbacks for its physical cameras. For example,
+         * if app A opens the camera device:</p>
+         *
+         * <ul>
+         *
+         * <li>All apps subscribing to ActivityCallback get {@link #onCameraUnavailable}.</li>
+         *
+         * <li>No app (including app A) subscribing to ActivityCallback gets
+         * {@link #onPhysicalCameraAvailable} or {@link #onPhysicalCameraUnavailable}, because
+         * the logical camera is unavailable (some app is using it).</li>
+         *
+         * </ul>
          *
          * <p>The default implementation of this method does nothing.</p>
          *
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index c614cdb..72d8122 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -1433,10 +1433,17 @@
     }
 
     @NonNull
-    private static float[] createEnrollStageThresholds(@NonNull Context context) {
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    private float[] createEnrollStageThresholds(@NonNull Context context) {
         // TODO(b/200604947): Fetch this value from FingerprintService, rather than internal config
-        final String[] enrollStageThresholdStrings = context.getResources().getStringArray(
-                com.android.internal.R.array.config_udfps_enroll_stage_thresholds);
+        final String[] enrollStageThresholdStrings;
+        if (isPowerbuttonFps()) {
+            enrollStageThresholdStrings = context.getResources().getStringArray(
+                    com.android.internal.R.array.config_sfps_enroll_stage_thresholds);
+        } else {
+            enrollStageThresholdStrings = context.getResources().getStringArray(
+                    com.android.internal.R.array.config_udfps_enroll_stage_thresholds);
+        }
 
         final float[] enrollStageThresholds = new float[enrollStageThresholdStrings.length];
         for (int i = 0; i < enrollStageThresholds.length; i++) {
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/hardware/radio/ProgramSelector.java b/core/java/android/hardware/radio/ProgramSelector.java
index 6300a12..a13eada 100644
--- a/core/java/android/hardware/radio/ProgramSelector.java
+++ b/core/java/android/hardware/radio/ProgramSelector.java
@@ -491,8 +491,12 @@
     public String toString() {
         StringBuilder sb = new StringBuilder("ProgramSelector(type=").append(mProgramType)
                 .append(", primary=").append(mPrimaryId);
-        if (mSecondaryIds.length > 0) sb.append(", secondary=").append(mSecondaryIds);
-        if (mVendorIds.length > 0) sb.append(", vendor=").append(mVendorIds);
+        if (mSecondaryIds.length > 0) {
+            sb.append(", secondary=").append(Arrays.toString(mSecondaryIds));
+        }
+        if (mVendorIds.length > 0) {
+            sb.append(", vendor=").append(Arrays.toString(mVendorIds));
+        }
         sb.append(")");
         return sb.toString();
     }
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 8180caa..4334116 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -505,7 +505,8 @@
         public int hashCode() {
             return Objects.hash(mId, mServiceName, mClassId, mImplementor, mProduct, mVersion,
                 mSerial, mNumTuners, mNumAudioSources, mIsInitializationRequired,
-                mIsCaptureSupported, mBands, mIsBgScanSupported, mDabFrequencyTable, mVendorInfo);
+                mIsCaptureSupported, Arrays.hashCode(mBands), mIsBgScanSupported,
+                mDabFrequencyTable, mVendorInfo);
         }
 
         @Override
@@ -525,7 +526,7 @@
             if (mNumAudioSources != other.mNumAudioSources) return false;
             if (mIsInitializationRequired != other.mIsInitializationRequired) return false;
             if (mIsCaptureSupported != other.mIsCaptureSupported) return false;
-            if (!Objects.equals(mBands, other.mBands)) return false;
+            if (!Arrays.equals(mBands, other.mBands)) return false;
             if (mIsBgScanSupported != other.mIsBgScanSupported) return false;
             if (!Objects.equals(mDabFrequencyTable, other.mDabFrequencyTable)) return false;
             if (!Objects.equals(mVendorInfo, other.mVendorInfo)) return false;
diff --git a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
index 84c3623..5ce38e9 100644
--- a/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
+++ b/core/java/android/inputmethodservice/IRemoteInputConnectionInvoker.java
@@ -33,6 +33,8 @@
 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.SurroundingText;
 import android.view.inputmethod.TextAttribute;
@@ -633,16 +635,11 @@
     }
 
     /**
-     * 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#performHandwritingDeleteGesture},
+     * {@link IRemoteInputConnection#performHandwritingInsertGesture},
+     * {@link IRemoteInputConnection#performHandwritingRemoveSpaceGesture},
+     * {@link IRemoteInputConnection#performHandwritingJoinOrSplitGesture}.
      */
     @AnyThread
     public void performHandwritingGesture(
@@ -664,6 +661,12 @@
             } else if (gesture instanceof DeleteGesture) {
                 mConnection.performHandwritingDeleteGesture(
                         createHeader(), (DeleteGesture) 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/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 48b9b88..3a157d3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -107,6 +107,7 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
+import android.view.MotionEvent.ToolType;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
@@ -947,7 +948,7 @@
          * @hide
          */
         @Override
-        public void updateEditorToolType(int toolType) {
+        public void updateEditorToolType(@ToolType int toolType) {
             onUpdateEditorToolType(toolType);
         }
 
@@ -3079,10 +3080,13 @@
      * {@link MotionEvent#getToolType(int)} was used to click the editor.
      * e.g. when toolType is {@link MotionEvent#TOOL_TYPE_STYLUS}, IME may choose to show a
      * companion widget instead of normal virtual keyboard.
+     * <p> This method is called after {@link #onStartInput(EditorInfo, boolean)} and before
+     * {@link #onStartInputView(EditorInfo, boolean)} when editor was clicked with a known tool
+     * type.</p>
      * <p> Default implementation does nothing. </p>
      * @param toolType what {@link MotionEvent#getToolType(int)} was used to click on editor.
      */
-    public void onUpdateEditorToolType(int toolType) {
+    public void onUpdateEditorToolType(@ToolType int toolType) {
         // Intentionally empty
     }
 
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index a19eb56..8644d91 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -23,6 +23,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
+import java.util.Arrays;
 
 
 /**
@@ -395,7 +396,7 @@
             out[i * 2] = entries.keyAt(i);
             out[i * 2 + 1] = entries.valueAt(i);
         }
-        int size = out.toString().getBytes().length;
+        int size = Arrays.toString(out).getBytes().length;
         if (size > MAX_SERIALIZED_SIZE) {
             Log.i(TAG, "Log line too long, did not emit: " + size + " bytes.");
             throw new RuntimeException();
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index ba0546a..3979c6c 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -171,7 +171,7 @@
         mPassword = password;
         mRsaPrivateKey = rsaPrivateKey;
         mUserCert = userCert;
-        mProxyInfo = new ProxyInfo(proxyInfo);
+        mProxyInfo = (proxyInfo == null) ? null : new ProxyInfo(proxyInfo);
 
         // UnmodifiableList doesn't make a defensive copy by default.
         mAllowedAlgorithms = Collections.unmodifiableList(new ArrayList<>(allowedAlgorithms));
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 da20626..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;
@@ -1767,6 +1767,49 @@
     }
 
     /**
+     * Measured energy delta from the previous reading.
+     */
+    public static final class MeasuredEnergyDetails {
+        /**
+         * Description of the energy consumer, such as CPU, DISPLAY etc
+         */
+        public static final class EnergyConsumer {
+            /**
+             * See android.hardware.power.stats.EnergyConsumerType
+             */
+            public int type;
+            /**
+             * Used when there are multipe energy consumers of the same type, such
+             * as CPU clusters, multiple displays on foldable devices etc.
+             */
+            public int ordinal;
+            /**
+             * Human-readable name of the energy consumer, e.g. "CPU"
+             */
+            public String name;
+        }
+        public EnergyConsumer[] consumers;
+        public long[] chargeUC;
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < consumers.length; i++) {
+                if (chargeUC[i] == POWER_DATA_UNAVAILABLE) {
+                    continue;
+                }
+                if (sb.length() != 0) {
+                    sb.append(' ');
+                }
+                sb.append(consumers[i].name);
+                sb.append('=');
+                sb.append(chargeUC[i]);
+            }
+            return sb.toString();
+        }
+    }
+
+    /**
      * Battery history record.
      */
     public static final class HistoryItem {
@@ -1886,6 +1929,7 @@
         public static final int STATE2_BLUETOOTH_SCAN_FLAG = 1 << 20;
         public static final int STATE2_CELLULAR_HIGH_TX_POWER_FLAG = 1 << 19;
         public static final int STATE2_USB_DATA_LINK_FLAG = 1 << 18;
+        public static final int STATE2_EXTENSIONS_FLAG = 1 << 17;
 
         public static final int MOST_INTERESTING_STATES2 =
                 STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_MASK
@@ -1905,6 +1949,9 @@
         // Non-null when there is more detailed information at this step.
         public HistoryStepDetails stepDetails;
 
+        // Non-null when there is measured energy information
+        public MeasuredEnergyDetails measuredEnergyDetails;
+
         public static final int EVENT_FLAG_START = 0x8000;
         public static final int EVENT_FLAG_FINISH = 0x4000;
 
@@ -2113,6 +2160,7 @@
             eventCode = EVENT_NONE;
             eventTag = null;
             tagsFirstOccurrence = false;
+            measuredEnergyDetails = null;
         }
 
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -2162,6 +2210,7 @@
             }
             tagsFirstOccurrence = o.tagsFirstOccurrence;
             currentTime = o.currentTime;
+            measuredEnergyDetails = o.measuredEnergyDetails;
         }
 
         public boolean sameNonEvent(HistoryItem o) {
@@ -6951,6 +7000,14 @@
                         item.append("\"");
                     }
                 }
+                if ((rec.states2 & HistoryItem.STATE2_EXTENSIONS_FLAG) != 0) {
+                    if (!checkin) {
+                        item.append(" ext=");
+                        if (rec.measuredEnergyDetails != null) {
+                            item.append("E");
+                        }
+                    }
+                }
                 if (rec.eventCode != HistoryItem.EVENT_NONE) {
                     item.append(checkin ? "," : " ");
                     if ((rec.eventCode&HistoryItem.EVENT_FLAG_START) != 0) {
@@ -7075,6 +7132,25 @@
                         item.append("\n");
                     }
                 }
+                if (rec.measuredEnergyDetails != null) {
+                    if (!checkin) {
+                        item.append("                 Energy: ");
+                        item.append(rec.measuredEnergyDetails);
+                        item.append("\n");
+                    } else {
+                        item.append(BATTERY_STATS_CHECKIN_VERSION); item.append(',');
+                        item.append(HISTORY_DATA); item.append(",0,XE");
+                        for (int i = 0; i < rec.measuredEnergyDetails.consumers.length; i++) {
+                            if (rec.measuredEnergyDetails.chargeUC[i] != POWER_DATA_UNAVAILABLE) {
+                                item.append(',');
+                                item.append(rec.measuredEnergyDetails.consumers[i].name);
+                                item.append('=');
+                                item.append(rec.measuredEnergyDetails.chargeUC[i]);
+                            }
+                        }
+                        item.append("\n");
+                    }
+                }
                 oldState = rec.states;
                 oldState2 = rec.states2;
                 // Clear High Tx Power Flag for volta positioning
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..4f26ad2 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -1262,8 +1262,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 +1278,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/Bundle.java b/core/java/android/os/Bundle.java
index 7e355d9..e845ffa 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -934,6 +934,12 @@
      * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
      * Otherwise, this method might throw an exception or return {@code null}.
      *
+     * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #getParcelable(String)} instead.
+     *
      * @param key a String, or {@code null}
      * @param clazz The type of the object expected
      * @return a Parcelable value, or {@code null}
@@ -990,6 +996,13 @@
      * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
      * Otherwise, this method might throw an exception or return {@code null}.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #getParcelableArray(String)} instead.
+     *
      * @param key a String, or {@code null}
      * @param clazz The type of the items inside the array. This is only verified when unparceling.
      * @return a Parcelable[] value, or {@code null}
@@ -1054,6 +1067,13 @@
      * you must call {@link #setClassLoader(ClassLoader)} with the proper {@link ClassLoader} first.
      * Otherwise, this method might throw an exception or return {@code null}.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #getParcelableArrayList(String)} instead.
+     *
      * @param key   a String, or {@code null}
      * @param clazz The type of the items inside the array list. This is only verified when
      *     unparceling.
@@ -1105,6 +1125,13 @@
      *     <li>The object is not of type {@code clazz}.
      * </ul>
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #getSparseParcelableArray(String)} instead.
+     *
      * @param key a String, or null
      * @param clazz The type of the items inside the sparse array. This is only verified when
      *     unparceling.
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 43a6be5..fb8f84a 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -469,7 +469,15 @@
      * 2) The per-application switch (i.e. Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS and
      *    Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES; which corresponds to the
      *    “angle_gl_driver_selection_pkgs” and “angle_gl_driver_selection_values” settings); if it
-     *    forces a choice; otherwise ...
+     *    forces a choice;
+     *      - Workaround Note: ANGLE and Vulkan currently have issues with applications that use YUV
+     *        target functionality.  The ANGLE broadcast receiver code will apply a "deferlist" at
+     *        the first boot of a newly-flashed device.  However, there is a gap in time between
+     *        when applications can start and when the deferlist is applied.  For now, assume that
+     *        if ANGLE is the system driver and Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS is
+     *        empty, that the deferlist has not yet been applied.  In this case, select the Legacy
+     *        driver.
+     *    otherwise ...
      * 3) Use ANGLE if isAngleEnabledByGameMode() returns true; otherwise ...
      * 4) The global switch (i.e. use the system driver, whether ANGLE or legacy;
      *    a.k.a. mAngleIsSystemDriver, which is set by the device’s “ro.hardware.egl” property)
@@ -509,9 +517,16 @@
         final List<String> optInValues = getGlobalSettingsString(
                 contentResolver, bundle, Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES);
         Log.v(TAG, "Currently set values for:");
-        Log.v(TAG, "  angle_gl_driver_selection_pkgs = " + optInPackages);
+        Log.v(TAG, "    angle_gl_driver_selection_pkgs =" + optInPackages);
         Log.v(TAG, "  angle_gl_driver_selection_values =" + optInValues);
 
+        // If ANGLE is the system driver AND the deferlist has not yet been applied, select the
+        // Legacy driver
+        if (mAngleIsSystemDriver && optInPackages.size() <= 1) {
+            Log.v(TAG, "Ignoring angle_gl_driver_selection_* until deferlist has been applied");
+            return ANGLE_GL_DRIVER_TO_USE_LEGACY;
+        }
+
         // Make sure we have good settings to use
         if (optInPackages.size() != optInValues.size()) {
             Log.w(TAG,
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 1f3108a..d84037f 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -16,6 +16,7 @@
 # Multiuser
 per-file IUser* = file:/MULTIUSER_OWNERS
 per-file User* = file:/MULTIUSER_OWNERS
+per-file NewUser* = file:/MULTIUSER_OWNERS
 
 # Binder
 per-file BadParcelableException.java = file:platform/frameworks/native:/libs/binder/OWNERS
diff --git a/core/java/android/os/PackageTagsList.java b/core/java/android/os/PackageTagsList.java
index 4a81dc6..df99074 100644
--- a/core/java/android/os/PackageTagsList.java
+++ b/core/java/android/os/PackageTagsList.java
@@ -26,6 +26,7 @@
 import com.android.internal.annotations.Immutable;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Objects;
@@ -140,6 +141,17 @@
         return true;
     }
 
+    /**
+     * Returns a list of packages.
+     *
+     * @deprecated Do not use.
+     * @hide
+     */
+    @Deprecated
+    public @NonNull Collection<String> getPackages() {
+        return new ArrayList<>(mPackageTags.keySet());
+    }
+
     public static final @NonNull Parcelable.Creator<PackageTagsList> CREATOR =
             new Parcelable.Creator<PackageTagsList>() {
                 @SuppressWarnings("unchecked")
@@ -217,7 +229,7 @@
                     if (j > 0) {
                         pw.print(", ");
                     }
-                    if (attributionTag.startsWith(packageName)) {
+                    if (attributionTag != null && attributionTag.startsWith(packageName)) {
                         pw.print(attributionTag.substring(packageName.length()));
                     } else {
                         pw.print(attributionTag);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 80201d3..9189c6c 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3266,6 +3266,13 @@
      * Same as {@link #readList(List, ClassLoader)} but accepts {@code clazz} parameter as
      * the type required for each item.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readList(List, ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
@@ -3494,6 +3501,13 @@
      * Same as {@link #readArrayList(ClassLoader)} but accepts {@code clazz} parameter as
      * the type required for each item.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readArrayList(ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
@@ -3528,6 +3542,13 @@
      * Same as {@link #readArray(ClassLoader)} but accepts {@code clazz} parameter as
      * the type required for each item.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readArray(ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
@@ -3561,6 +3582,13 @@
      * Same as {@link #readSparseArray(ClassLoader)} but accepts {@code clazz} parameter as
      * the type required for each item.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readSparseArray(ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
@@ -3878,6 +3906,13 @@
      * Same as {@link #readParcelableList(List, ClassLoader)} but accepts {@code clazz} parameter as
      * the type required for each item.
      *
+     * <p><b>Warning: </b> if the list contains items implementing the {@link Parcelable} interface,
+     * the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readParcelableList(List, ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
@@ -4775,6 +4810,12 @@
      * Same as {@link #readParcelable(ClassLoader)} but accepts {@code clazz} parameter as the type
      * required for each item.
      *
+     * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readParcelable(ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
@@ -4843,6 +4884,12 @@
      * Same as {@link #readParcelableCreator(ClassLoader)} but accepts {@code clazz} parameter
      * as the required type.
      *
+     * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readParcelableCreator(ClassLoader) instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there there was an error
      * trying to read the {@link Parcelable.Creator}.
@@ -4979,6 +5026,12 @@
      * Same as {@link #readParcelableArray(ClassLoader)}  but accepts {@code clazz} parameter as
      * the type required for each item.
      *
+     * <p><b>Warning: </b> the class that implements {@link Parcelable} has to be the immediately
+     * enclosing class of the runtime type of its CREATOR field (that is,
+     * {@link Class#getEnclosingClass()} has to return the parcelable implementing class),
+     * otherwise this method might throw an exception. If the Parcelable class does not enclose the
+     * CREATOR, use the deprecated {@link #readParcelableArray(ClassLoader)} instead.
+     *
      * @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
      * is not an instance of that class or any of its children classes or there was an error
      * trying to instantiate an element.
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/StrictMode.java b/core/java/android/os/StrictMode.java
index 412a33a..113a640 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -26,6 +26,9 @@
 import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.app.IActivityManager;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -344,6 +347,13 @@
     public static final int NETWORK_POLICY_LOG = 1;
     /** {@hide} */
     public static final int NETWORK_POLICY_REJECT = 2;
+  
+    /**
+     * Detect explicit calls to {@link Runtime#gc()}.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    static final long DETECT_EXPLICIT_GC = 3400644L;
 
     // TODO: wrap in some ImmutableHashMap thing.
     // Note: must be before static initialization of sVmPolicy.
@@ -496,6 +506,7 @@
              * <p>As of the Gingerbread release this includes network and disk operations but will
              * likely expand in future releases.
              */
+            @SuppressWarnings("AndroidFrameworkCompatChange")
             public @NonNull Builder detectAll() {
                 detectDiskReads();
                 detectDiskWrites();
@@ -511,6 +522,9 @@
                 if (targetSdk >= Build.VERSION_CODES.O) {
                     detectUnbufferedIo();
                 }
+                if (CompatChanges.isChangeEnabled(DETECT_EXPLICIT_GC)) {
+                    detectExplicitGc();
+                }
                 return this;
             }
 
@@ -591,26 +605,16 @@
             }
 
             /**
-             * Detect explicit GC requests, i.e. calls to Runtime.gc().
-             *
-             * @hide
+             * Detect calls to {@link Runtime#gc()}.
              */
-            @TestApi
             public @NonNull Builder detectExplicitGc() {
-                // TODO(b/3400644): Un-hide this for next API update
-                // TODO(b/3400644): Un-hide ExplicitGcViolation for next API update
-                // TODO(b/3400644): Make DETECT_EXPLICIT_GC a @TestApi for next API update
-                // TODO(b/3400644): Call this from detectAll in next API update
                 return enable(DETECT_THREAD_EXPLICIT_GC);
             }
 
             /**
-             * Disable detection of explicit GC requests, i.e. calls to Runtime.gc().
-             *
-             * @hide
+             * Disable detection of calls to {@link Runtime#gc()}.
              */
             public @NonNull Builder permitExplicitGc() {
-                // TODO(b/3400644): Un-hide this for next API update
                 return disable(DETECT_THREAD_EXPLICIT_GC);
             }
 
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 06930bb..b2d62eb 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -145,7 +145,9 @@
      */
     @IntDef(prefix = { "FLAG_" }, flag = true, value = {
             FLAG_BYPASS_INTERRUPTION_POLICY,
-            FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
+            FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF,
+            FLAG_INVALIDATE_SETTINGS_CACHE,
+            FLAG_PIPELINED_EFFECT
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Flag{}
@@ -156,7 +158,7 @@
      * <p>Only privileged apps can ignore user settings that limit interruptions, and this
      * flag will be ignored otherwise.
      */
-    public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1;
+    public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 1;
 
     /**
      * Flag requesting vibration effect to be played even when user settings are disabling it.
@@ -167,7 +169,7 @@
      *
      * @hide
      */
-    public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 0x2;
+    public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 1 << 1;
 
     /**
      * Flag requesting vibration effect to be played with fresh user settings values.
@@ -182,7 +184,19 @@
      *
      * @hide
      */
-    public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 0x3;
+    public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 1 << 2;
+
+    /**
+     * Flag requesting that this vibration effect be pipelined with other vibration effects from the
+     * same package that also carry this flag.
+     *
+     * <p>Pipelined effects won't cancel a running pipelined effect, but will instead play after
+     * it completes. However, only one pipelined effect can be waiting at a time - so if an effect
+     * is already waiting (but not running), it will be cancelled in favor of a newer one.
+     *
+     * @hide
+     */
+    public static final int FLAG_PIPELINED_EFFECT = 1 << 3;
 
     /**
      * All flags supported by vibrator service, update it when adding new flag.
@@ -190,7 +204,7 @@
      */
     public static final int FLAG_ALL_SUPPORTED =
             FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF
-                    | FLAG_INVALIDATE_SETTINGS_CACHE;
+                    | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT;
 
     /** Creates a new {@link VibrationAttributes} instance with given usage. */
     public static @NonNull VibrationAttributes createForUsage(@Usage int usage) {
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/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 13b22d3..a1ed253 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -26,6 +26,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.nio.ByteBuffer;
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.UUID;
 
@@ -515,7 +516,7 @@
             throw new IOException("Unsupported log2BlockSize: " + hashingInfo.log2BlockSize);
         }
         if (hashingInfo.salt != null && hashingInfo.salt.length > 0) {
-            throw new IOException("Unsupported salt: " + hashingInfo.salt);
+            throw new IOException("Unsupported salt: " + Arrays.toString(hashingInfo.salt));
         }
         if (hashingInfo.rawRootHash.length != INCFS_MAX_HASH_SIZE) {
             throw new IOException("rawRootHash has to be " + INCFS_MAX_HASH_SIZE + " bytes");
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/os/strictmode/ExplicitGcViolation.java b/core/java/android/os/strictmode/ExplicitGcViolation.java
index 583ed1a..c4ae82d 100644
--- a/core/java/android/os/strictmode/ExplicitGcViolation.java
+++ b/core/java/android/os/strictmode/ExplicitGcViolation.java
@@ -19,10 +19,7 @@
 
 /**
  * See #{@link android.os.StrictMode.ThreadPolicy.Builder#detectExplicitGc()}.
- *
- * @hide
  */
-@TestApi
 public final class ExplicitGcViolation extends Violation {
     /** @hide */
     public ExplicitGcViolation() {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index b7adcb8..d125cbb 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -775,6 +775,14 @@
      */
     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";
+
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/core/java/android/provider/InputMethodManagerDeviceConfig.java
similarity index 61%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to core/java/android/provider/InputMethodManagerDeviceConfig.java
index e62a63a..906b133 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/core/java/android/provider/InputMethodManagerDeviceConfig.java
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.desktopmode;
+package android.provider;
 
-import android.os.SystemProperties;
+import android.annotation.TestApi;
 
 /**
- * Constants for desktop mode feature
+ * Interface for accessing keys belonging to {@link DeviceConfig#NAMESPACE_INPUT_METHOD_MANAGER}.
+ * @hide
  */
-public class DesktopModeConstants {
-
+@TestApi
+public interface InputMethodManagerDeviceConfig {
     /**
-     * Flag to indicate whether desktop mode is available on the device
+     * Whether the IME should be hidden when the window gained focus without an editor focused.
      */
-    public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+    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/service/autofill/OptionalValidators.java b/core/java/android/service/autofill/OptionalValidators.java
index 7189c88..2043539 100644
--- a/core/java/android/service/autofill/OptionalValidators.java
+++ b/core/java/android/service/autofill/OptionalValidators.java
@@ -25,6 +25,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Arrays;
+
 /**
  * Compound validator that returns {@code true} on {@link #isValid(ValueFinder)} if any
  * of its subvalidators returns {@code true} as well.
@@ -61,7 +63,8 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        return new StringBuilder("OptionalValidators: [validators=").append(mValidators)
+        return new StringBuilder("OptionalValidators: [validators=")
+                .append(Arrays.toString(mValidators))
                 .append("]")
                 .toString();
     }
diff --git a/core/java/android/service/autofill/RequiredValidators.java b/core/java/android/service/autofill/RequiredValidators.java
index 619eba0..054582e 100644
--- a/core/java/android/service/autofill/RequiredValidators.java
+++ b/core/java/android/service/autofill/RequiredValidators.java
@@ -25,6 +25,8 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.util.Arrays;
+
 /**
  * Compound validator that only returns {@code true} on {@link #isValid(ValueFinder)} if all
  * of its subvalidators return {@code true} as well.
@@ -60,7 +62,8 @@
     public String toString() {
         if (!sDebug) return super.toString();
 
-        return new StringBuilder("RequiredValidators: [validators=").append(mValidators)
+        return new StringBuilder("RequiredValidators: [validators=")
+                .append(Arrays.toString(mValidators))
                 .append("]")
                 .toString();
     }
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 7bf5c38..6956cd4 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -46,6 +46,12 @@
     public abstract boolean isDreaming();
 
     /**
+     * Ask the power manager to nap.  It will eventually call back into startDream() if/when it is
+     * appropriate to start dreaming.
+     */
+    public abstract void requestDream();
+
+    /**
      * Called by the ActivityTaskManagerService to verify that the startDreamActivity
      * request comes from the current active dream component.
      *
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index b0c5d83..6f5212c 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
 import android.app.Activity;
 import android.app.ActivityTaskManager;
 import android.app.AlarmManager;
@@ -1124,7 +1125,8 @@
      * @hide
      */
     @Nullable
-    public static DreamMetadata getDreamMetadata(Context context,
+    @TestApi
+    public static DreamMetadata getDreamMetadata(@NonNull Context context,
             @Nullable ServiceInfo serviceInfo) {
         if (serviceInfo == null) return null;
 
@@ -1183,7 +1185,8 @@
         }
     }
 
-    private static ComponentName convertToComponentName(String flattenedString,
+    @Nullable
+    private static ComponentName convertToComponentName(@Nullable String flattenedString,
             ServiceInfo serviceInfo) {
         if (flattenedString == null) {
             return null;
@@ -1193,7 +1196,17 @@
             return new ComponentName(serviceInfo.packageName, flattenedString);
         }
 
-        return ComponentName.unflattenFromString(flattenedString);
+        // Ensure that the component is from the same package as the dream service. If not,
+        // treat the component as invalid and return null instead.
+        final ComponentName cn = ComponentName.unflattenFromString(flattenedString);
+        if (cn == null) return null;
+        if (!cn.getPackageName().equals(serviceInfo.packageName)) {
+            Log.w(TAG,
+                    "Inconsistent package name in component: " + cn.getPackageName()
+                            + ", should be: " + serviceInfo.packageName);
+            return null;
+        }
+        return cn;
     }
 
     /**
@@ -1489,6 +1502,7 @@
      *
      * @hide
      */
+    @TestApi
     public static final class DreamMetadata {
         @Nullable
         public final ComponentName settingsActivity;
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 53ae657..609425c 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -43,5 +43,6 @@
     void forceAmbientDisplayEnabled(boolean enabled);
     ComponentName[] getDreamComponentsForUser(int userId);
     void setDreamComponentsForUser(int userId, in ComponentName[] componentNames);
+    void setSystemDreamComponent(in ComponentName componentName);
     void registerDreamOverlayService(in ComponentName componentName);
 }
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index ced2a01..fae72a2 100644
--- a/core/java/android/service/dreams/Sandman.java
+++ b/core/java/android/service/dreams/Sandman.java
@@ -20,13 +20,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
+
 /**
  * Internal helper for launching dreams to ensure consistency between the
  * <code>UiModeManagerService</code> system service and the <code>Somnambulator</code> activity.
@@ -75,32 +75,28 @@
     }
 
     private static void startDream(Context context, boolean docked) {
-        try {
-            IDreamManager dreamManagerService = IDreamManager.Stub.asInterface(
-                    ServiceManager.getService(DreamService.DREAM_SERVICE));
-            if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
-                if (docked) {
-                    Slog.i(TAG, "Activating dream while docked.");
+        DreamManagerInternal dreamManagerService =
+                LocalServices.getService(DreamManagerInternal.class);
+        if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
+            if (docked) {
+                Slog.i(TAG, "Activating dream while docked.");
 
-                    // Wake up.
-                    // The power manager will wake up the system automatically when it starts
-                    // receiving power from a dock but there is a race between that happening
-                    // and the UI mode manager starting a dream.  We want the system to already
-                    // be awake by the time this happens.  Otherwise the dream may not start.
-                    PowerManager powerManager =
-                            context.getSystemService(PowerManager.class);
-                    powerManager.wakeUp(SystemClock.uptimeMillis(),
-                            PowerManager.WAKE_REASON_PLUGGED_IN,
-                            "android.service.dreams:DREAM");
-                } else {
-                    Slog.i(TAG, "Activating dream by user request.");
-                }
-
-                // Dream.
-                dreamManagerService.dream();
+                // Wake up.
+                // The power manager will wake up the system automatically when it starts
+                // receiving power from a dock but there is a race between that happening
+                // and the UI mode manager starting a dream.  We want the system to already
+                // be awake by the time this happens.  Otherwise the dream may not start.
+                PowerManager powerManager =
+                        context.getSystemService(PowerManager.class);
+                powerManager.wakeUp(SystemClock.uptimeMillis(),
+                        PowerManager.WAKE_REASON_PLUGGED_IN,
+                        "android.service.dreams:DREAM");
+            } else {
+                Slog.i(TAG, "Activating dream by user request.");
             }
-        } catch (RemoteException ex) {
-            Slog.e(TAG, "Could not start dream when docked.", ex);
+
+            // Dream.
+            dreamManagerService.requestDream();
         }
     }
 
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/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/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 59f1e8e..55e2c17 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -40,5 +40,5 @@
     void closeSystemDialogs();
     void onLockscreenShown();
     void destroy();
-    void updateVisibleActivityInfo(in VisibleActivityInfo visibleActivityInfo, int type);
+    void notifyVisibleActivityInfoChanged(in VisibleActivityInfo visibleActivityInfo, int type);
 }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index d08a67e..82e1d5f0 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -75,6 +75,7 @@
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -360,9 +361,10 @@
         }
 
         @Override
-        public void updateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) {
+        public void notifyVisibleActivityInfoChanged(VisibleActivityInfo visibleActivityInfo,
+                int type) {
             mHandlerCaller.sendMessage(
-                    mHandlerCaller.obtainMessageIO(MSG_UPDATE_VISIBLE_ACTIVITY_INFO, type,
+                    mHandlerCaller.obtainMessageIO(MSG_NOTIFY_VISIBLE_ACTIVITY_INFO_CHANGED, type,
                             visibleActivityInfo));
         }
     };
@@ -599,7 +601,7 @@
                 VoiceInteractor.PickOptionRequest.Option[] selections, Bundle result) {
             try {
                 if (DEBUG) Log.d(TAG, "sendPickOptionResult: req=" + mInterface
-                        + " finished=" + finished + " selections=" + selections
+                        + " finished=" + finished + " selections=" + Arrays.toString(selections)
                         + " result=" + result);
                 if (finished) {
                     finishRequest();
@@ -856,7 +858,7 @@
     static final int MSG_SHOW = 106;
     static final int MSG_HIDE = 107;
     static final int MSG_ON_LOCKSCREEN_SHOWN = 108;
-    static final int MSG_UPDATE_VISIBLE_ACTIVITY_INFO = 109;
+    static final int MSG_NOTIFY_VISIBLE_ACTIVITY_INFO_CHANGED = 109;
     static final int MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK = 110;
     static final int MSG_UNREGISTER_VISIBLE_ACTIVITY_CALLBACK = 111;
 
@@ -944,12 +946,13 @@
                     if (DEBUG) Log.d(TAG, "onLockscreenShown");
                     onLockscreenShown();
                     break;
-                case MSG_UPDATE_VISIBLE_ACTIVITY_INFO:
+                case MSG_NOTIFY_VISIBLE_ACTIVITY_INFO_CHANGED:
                     if (DEBUG) {
-                        Log.d(TAG, "doUpdateVisibleActivityInfo: visibleActivityInfo=" + msg.obj
-                                + " type=" + msg.arg1);
+                        Log.d(TAG,
+                                "doNotifyVisibleActivityInfoChanged: visibleActivityInfo=" + msg.obj
+                                        + " type=" + msg.arg1);
                     }
-                    doUpdateVisibleActivityInfo((VisibleActivityInfo) msg.obj, msg.arg1);
+                    doNotifyVisibleActivityInfoChanged((VisibleActivityInfo) msg.obj, msg.arg1);
                     break;
                 case MSG_REGISTER_VISIBLE_ACTIVITY_CALLBACK:
                     if (DEBUG) {
@@ -1177,7 +1180,8 @@
         }
     }
 
-    private void doUpdateVisibleActivityInfo(VisibleActivityInfo visibleActivityInfo, int type) {
+    private void doNotifyVisibleActivityInfoChanged(VisibleActivityInfo visibleActivityInfo,
+            int type) {
 
         if (mVisibleActivityCallbacks.isEmpty()) {
             return;
@@ -1185,11 +1189,11 @@
 
         switch (type) {
             case VisibleActivityInfo.TYPE_ACTIVITY_ADDED:
-                informVisibleActivityChanged(visibleActivityInfo, type);
+                notifyVisibleActivityChanged(visibleActivityInfo, type);
                 mVisibleActivityInfos.add(visibleActivityInfo);
                 break;
             case VisibleActivityInfo.TYPE_ACTIVITY_REMOVED:
-                informVisibleActivityChanged(visibleActivityInfo, type);
+                notifyVisibleActivityChanged(visibleActivityInfo, type);
                 mVisibleActivityInfos.remove(visibleActivityInfo);
                 break;
         }
@@ -1234,7 +1238,7 @@
         }
     }
 
-    private void informVisibleActivityChanged(VisibleActivityInfo visibleActivityInfo, int type) {
+    private void notifyVisibleActivityChanged(VisibleActivityInfo visibleActivityInfo, int type) {
         for (Map.Entry<VisibleActivityCallback, Executor> e :
                 mVisibleActivityCallbacks.entrySet()) {
             final Executor executor = e.getValue();
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index bc8822c..be8c140 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -518,7 +518,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() {
diff --git a/core/java/android/speech/tts/FileSynthesisCallback.java b/core/java/android/speech/tts/FileSynthesisCallback.java
index 3bde32b..3177c5c 100644
--- a/core/java/android/speech/tts/FileSynthesisCallback.java
+++ b/core/java/android/speech/tts/FileSynthesisCallback.java
@@ -24,6 +24,7 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.FileChannel;
+import java.util.Arrays;
 
 /**
  * Speech synthesis request that writes the audio to a WAV file.
@@ -152,8 +153,8 @@
     @Override
     public int audioAvailable(byte[] buffer, int offset, int length) {
         if (DBG) {
-            Log.d(TAG, "FileSynthesisRequest.audioAvailable(" + buffer + "," + offset
-                    + "," + length + ")");
+            Log.d(TAG, "FileSynthesisRequest.audioAvailable(" + Arrays.toString(buffer)
+                    + "," + offset + "," + length + ")");
         }
         FileChannel fileChannel = null;
         synchronized (mStateLock) {
diff --git a/core/java/android/text/GraphemeClusterSegmentIterator.java b/core/java/android/text/GraphemeClusterSegmentIterator.java
new file mode 100644
index 0000000..e3976a7
--- /dev/null
+++ b/core/java/android/text/GraphemeClusterSegmentIterator.java
@@ -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 android.text;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.graphics.Paint;
+
+/**
+ * Implementation of {@code SegmentIterator} using grapheme clusters as the text segment. Whitespace
+ * characters are included as segments.
+ *
+ * @hide
+ */
+public class GraphemeClusterSegmentIterator extends SegmentIterator {
+    private final CharSequence mText;
+    private final TextPaint mTextPaint;
+
+    public GraphemeClusterSegmentIterator(
+            @NonNull CharSequence text, @NonNull TextPaint textPaint) {
+        mText = text;
+        mTextPaint = textPaint;
+    }
+
+    @Override
+    public int previousStartBoundary(@IntRange(from = 0) int offset) {
+        int boundary = mTextPaint.getTextRunCursor(
+                mText, 0, mText.length(), false, offset, Paint.CURSOR_BEFORE);
+        return boundary == -1 ? DONE : boundary;
+    }
+
+    @Override
+    public int previousEndBoundary(@IntRange(from = 0) int offset) {
+        int boundary = mTextPaint.getTextRunCursor(
+                mText, 0, mText.length(), false, offset, Paint.CURSOR_BEFORE);
+        // Check that there is another cursor position before, otherwise this is not a valid
+        // end boundary.
+        if (mTextPaint.getTextRunCursor(
+                mText, 0, mText.length(), false, boundary, Paint.CURSOR_BEFORE) == -1) {
+            return DONE;
+        }
+        return boundary == -1 ? DONE : boundary;
+    }
+
+    @Override
+    public int nextStartBoundary(@IntRange(from = 0) int offset) {
+        int boundary = mTextPaint.getTextRunCursor(
+                mText, 0, mText.length(), false, offset, Paint.CURSOR_AFTER);
+        // Check that there is another cursor position after, otherwise this is not a valid
+        // start boundary.
+        if (mTextPaint.getTextRunCursor(
+                mText, 0, mText.length(), false, boundary, Paint.CURSOR_AFTER) == -1) {
+            return DONE;
+        }
+        return boundary == -1 ? DONE : boundary;
+    }
+
+    @Override
+    public int nextEndBoundary(@IntRange(from = 0) int offset) {
+        int boundary = mTextPaint.getTextRunCursor(
+                mText, 0, mText.length(), false, offset, Paint.CURSOR_AFTER);
+        return boundary == -1 ? DONE : boundary;
+    }
+}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4efc838..b5f7c54 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -19,11 +19,13 @@
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.text.LineBreaker;
 import android.os.Build;
 import android.text.method.TextKeyListener;
@@ -710,8 +712,7 @@
     }
 
     /**
-     * Return the start position of the line, given the left and right bounds
-     * of the margins.
+     * Return the start position of the line, given the left and right bounds of the margins.
      *
      * @param line the line index
      * @param left the left bounds (0, or leading margin if ltr para)
@@ -1312,6 +1313,38 @@
         return horizontal;
     }
 
+    private void fillHorizontalBoundsForLine(int line, float[] horizontalBounds) {
+        final int lineStart = getLineStart(line);
+        final int lineEnd = getLineEnd(line);
+        final int lineLength = lineEnd - lineStart;
+
+        final int dir = getParagraphDirection(line);
+        final Directions directions = getLineDirections(line);
+
+        final boolean hasTab = getLineContainsTab(line);
+        TabStops tabStops = null;
+        if (hasTab && mText instanceof Spanned) {
+            // Just checking this line should be good enough, tabs should be
+            // consistent across all lines in a paragraph.
+            TabStopSpan[] tabs =
+                    getParagraphSpans((Spanned) mText, lineStart, lineEnd, TabStopSpan.class);
+            if (tabs.length > 0) {
+                tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+            }
+        }
+
+        final TextLine tl = TextLine.obtain();
+        tl.set(mPaint, mText, lineStart, lineEnd, dir, directions, hasTab, tabStops,
+                getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
+                isFallbackLineSpacingEnabled());
+        if (horizontalBounds == null || horizontalBounds.length < 2 * lineLength) {
+            horizontalBounds = new float[2 * lineLength];
+        }
+
+        tl.measureAllBounds(horizontalBounds, null);
+        TextLine.recycle(tl);
+    }
+
     /**
      * Return the characters' bounds in the given range. The {@code bounds} array will be filled
      * starting from {@code boundsStart} (inclusive). The coordinates are in local text layout.
@@ -1358,32 +1391,11 @@
             final int lineStart = getLineStart(line);
             final int lineEnd = getLineEnd(line);
             final int lineLength = lineEnd - lineStart;
-
-            final int dir = getParagraphDirection(line);
-            final boolean hasTab = getLineContainsTab(line);
-            final Directions directions = getLineDirections(line);
-
-            TabStops tabStops = null;
-            if (hasTab && mText instanceof Spanned) {
-                // Just checking this line should be good enough, tabs should be
-                // consistent across all lines in a paragraph.
-                TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, lineStart, lineEnd,
-                        TabStopSpan.class);
-                if (tabs.length > 0) {
-                    tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
-                }
-            }
-
-            final TextLine tl = TextLine.obtain();
-            tl.set(mPaint, mText, lineStart, lineEnd, dir, directions, hasTab, tabStops,
-                    getEllipsisStart(line), getEllipsisStart(line) + getEllipsisCount(line),
-                    isFallbackLineSpacingEnabled());
             if (horizontalBounds == null || horizontalBounds.length < 2 * lineLength) {
                 horizontalBounds = new float[2 * lineLength];
             }
+            fillHorizontalBoundsForLine(line, horizontalBounds);
 
-            tl.measureAllBounds(horizontalBounds, null);
-            TextLine.recycle(tl);
             final int lineLeft = getParagraphLeft(line);
             final int lineRight = getParagraphRight(line);
             final int lineStartPos = getLineStartPos(line, lineLeft, lineRight);
@@ -1802,6 +1814,380 @@
     }
 
     /**
+     * Finds the range of text which is inside the specified rectangle area. The start of the range
+     * is the start of the first text segment inside the area, and the end of the range is the end
+     * of the last text segment inside the area.
+     *
+     * <p>A text segment is considered to be inside the area if the center of its bounds is inside
+     * the area. If a text segment spans multiple lines or multiple directional runs (e.g. a
+     * hyphenated word), the text segment is divided into pieces at the line and run breaks, then
+     * the text segment is considered to be inside the area if any of its pieces have their center
+     * inside the area.
+     *
+     * <p>The returned range may also include text segments which are not inside the specified area,
+     * if those text segments are in between text segments which are inside the area. For example,
+     * the returned range may be "segment1 segment2 segment3" if "segment1" and "segment3" are
+     * inside the area and "segment2" is not.
+     *
+     * @param area area for which the text range will be found
+     * @param segmentIterator iterator for determining the ranges of text to be considered as a text
+     *     segment
+     * @return int array of size 2 containing the start (inclusive) and end (exclusive) character
+     *     offsets of the range, or null if there are no text segments inside the area
+     * @hide
+     */
+    @Nullable
+    public int[] getRangeForRect(@NonNull RectF area, @NonNull SegmentIterator segmentIterator) {
+        // Find the first line whose vertical center is below the top of the area.
+        int startLine = getLineForVertical((int) area.top);
+        int startLineTop = getLineTop(startLine);
+        int startLineBottom = getLineBottomWithoutSpacing(startLine);
+        if (area.top > (startLineTop + startLineBottom) / 2f) {
+            startLine++;
+            if (startLine >= getLineCount()) {
+                // The top of the area is below the vertical center of the last line, so the area
+                // does not contain any text.
+                return null;
+            }
+        }
+
+        // Find the last line whose vertical center is above the bottom of the area.
+        int endLine = getLineForVertical((int) area.bottom);
+        int endLineTop = getLineTop(endLine);
+        int endLineBottom = getLineBottomWithoutSpacing(endLine);
+        if (area.bottom < (endLineTop + endLineBottom) / 2f) {
+            endLine--;
+        }
+        if (endLine < startLine) {
+            // There are no lines with vertical centers between the top and bottom of the area, so
+            // the area does not contain any text.
+            return null;
+        }
+
+        int start = getStartOrEndOffsetForHorizontalInterval(
+                startLine, area.left, area.right, segmentIterator, /* getStart= */ true);
+        // If the area does not contain any text on this line, keep trying subsequent lines until
+        // the end line is reached.
+        while (start == -1 && startLine < endLine) {
+            startLine++;
+            start = getStartOrEndOffsetForHorizontalInterval(
+                    startLine, area.left, area.right, segmentIterator, /* getStart= */ true);
+        }
+        if (start == -1) {
+            // All lines were checked, the area does not contain any text.
+            return null;
+        }
+
+        int end = getStartOrEndOffsetForHorizontalInterval(
+                endLine, area.left, area.right, segmentIterator, /* getStart= */ false);
+        // If the area does not contain any text on this line, keep trying previous lines until
+        // the start line is reached.
+        while (end == -1 && startLine < endLine) {
+            endLine--;
+            end = getStartOrEndOffsetForHorizontalInterval(
+                    endLine, area.left, area.right, segmentIterator, /* getStart= */ false);
+        }
+        if (end == -1) {
+            // All lines were checked, the area does not contain any text.
+            return null;
+        }
+
+        // If a text segment spans multiple lines or multiple directional runs (e.g. a hyphenated
+        // word), then getStartOrEndOffsetForHorizontalInterval() can return an offset in the middle
+        // of a text segment. Adjust the range to include the rest of any partial text segments. If
+        // start is already the start boundary of a text segment, then this is a no-op.
+        start = segmentIterator.previousStartBoundary(start + 1);
+        end = segmentIterator.nextEndBoundary(end - 1);
+
+        return new int[] {start, end};
+    }
+
+    /**
+     * Finds the start character offset of the first text segment inside a horizontal interval
+     * within a line, or the end character offset of the last text segment inside the horizontal
+     * interval.
+     *
+     * @param line index of the line to search
+     * @param left left bound of the horizontal interval
+     * @param right right bound of the horizontal interval
+     * @param segmentIterator iterator for determining the ranges of text to be considered as a text
+     *     segment
+     * @param getStart true to find the start of the first text segment inside the horizontal
+     *     interval, false to find the end of the last text segment
+     * @return the start character offset of the first text segment inside the horizontal interval,
+     *     or the end character offset of the last text segment inside the horizontal interval.
+     */
+    private int getStartOrEndOffsetForHorizontalInterval(
+            @IntRange(from = 0) int line, float left, float right,
+            @NonNull SegmentIterator segmentIterator, boolean getStart) {
+        int lineStartOffset = getLineStart(line);
+        int lineEndOffset = getLineEnd(line);
+        if (lineStartOffset == lineEndOffset) {
+            return -1;
+        }
+
+        float[] horizontalBounds = new float[2 * (lineEndOffset - lineStartOffset)];
+        fillHorizontalBoundsForLine(line, horizontalBounds);
+
+        int lineStartPos = getLineStartPos(line, getParagraphLeft(line), getParagraphRight(line));
+
+        // Loop through the runs forwards or backwards depending on getStart value.
+        Layout.Directions directions = getLineDirections(line);
+        int runIndex = getStart ? 0 : directions.getRunCount() - 1;
+        while ((getStart && runIndex < directions.getRunCount()) || (!getStart && runIndex >= 0)) {
+            // runStartOffset and runEndOffset are offset indices within the line.
+            int runStartOffset = directions.getRunStart(runIndex);
+            int runEndOffset = Math.min(
+                    runStartOffset + directions.getRunLength(runIndex),
+                    lineEndOffset - lineStartOffset);
+            boolean isRtl = directions.isRunRtl(runIndex);
+            float runLeft = lineStartPos
+                    + (isRtl
+                            ? horizontalBounds[2 * (runEndOffset - 1)]
+                            : horizontalBounds[2 * runStartOffset]);
+            float runRight = lineStartPos
+                    + (isRtl
+                            ? horizontalBounds[2 * runStartOffset + 1]
+                            : horizontalBounds[2 * (runEndOffset - 1) + 1]);
+
+            int result =
+                    getStart
+                            ? getStartOffsetForHorizontalIntervalWithinRun(
+                            left, right, lineStartOffset, lineStartPos, horizontalBounds,
+                            runStartOffset, runEndOffset, runLeft, runRight, isRtl,
+                            segmentIterator)
+                            : getEndOffsetForHorizontalIntervalWithinRun(
+                                    left, right, lineStartOffset, lineStartPos, horizontalBounds,
+                                    runStartOffset, runEndOffset, runLeft, runRight, isRtl,
+                                    segmentIterator);
+            if (result >= 0) {
+                return result;
+            }
+
+            runIndex += getStart ? 1 : -1;
+        }
+        return -1;
+    }
+
+    /**
+     * Finds the start character offset of the first text segment inside a horizontal interval
+     * within a directional run.
+     *
+     * @param left left bound of the horizontal interval
+     * @param right right bound of the horizontal interval
+     * @param lineStartOffset start character offset of the line containing this run
+     * @param lineStartPos start position of the line containing this run
+     * @param horizontalBounds array containing the signed horizontal bounds of the characters in
+     *     the line. The left and right bounds of the character at offset i are stored at index (2 *
+     *     i) and index (2 * i + 1). Bounds are relative to {@code lineStartPos}.
+     * @param runStartOffset start offset of the run relative to {@code lineStartOffset}
+     * @param runEndOffset end offset of the run relative to {@code lineStartOffset}
+     * @param runLeft left bound of the run
+     * @param runRight right bound of the run
+     * @param isRtl whether the run is right-to-left
+     * @param segmentIterator iterator for determining the ranges of text to be considered as a text
+     *     segment
+     * @return the start character offset of the first text segment inside the horizontal interval
+     */
+    private static int getStartOffsetForHorizontalIntervalWithinRun(
+            float left, float right,
+            @IntRange(from = 0) int lineStartOffset,
+            @IntRange(from = 0) int lineStartPos,
+            @NonNull float[] horizontalBounds,
+            @IntRange(from = 0) int runStartOffset, @IntRange(from = 0) int runEndOffset,
+            float runLeft, float runRight,
+            boolean isRtl,
+            @NonNull SegmentIterator segmentIterator) {
+        if (runRight < left || runLeft > right) {
+            // The run does not overlap the interval.
+            return -1;
+        }
+
+        // Find the first character in the run whose bounds overlap with the interval.
+        // firstCharOffset is an offset index within the line.
+        int firstCharOffset;
+        if ((!isRtl && left <= runLeft) || (isRtl && right >= runRight)) {
+            firstCharOffset = runStartOffset;
+        } else {
+            int low = runStartOffset;
+            int high = runEndOffset;
+            int guess;
+            while (high - low > 1) {
+                guess = (high + low) / 2;
+                // Left edge of the character at guess
+                float pos = lineStartPos + horizontalBounds[2 * guess];
+                if ((!isRtl && pos > left) || (isRtl && pos < right)) {
+                    high = guess;
+                } else {
+                    low = guess;
+                }
+            }
+            // The interval bound is between the left edge of the character at low and the left edge
+            // of the character at high. For LTR text, this is within the character at low. For RTL
+            // text, this is within the character at high.
+            firstCharOffset = isRtl ? high : low;
+        }
+
+        // Find the first text segment containing this character (or, if no text segment contains
+        // this character, the first text segment after this character). All previous text segments
+        // in this run are to the left (for LTR) of the interval.
+        segmentIterator.setRunLimits(
+                lineStartOffset + runStartOffset, lineStartOffset + runEndOffset);
+        int segmentEndOffset =
+                segmentIterator.nextEndBoundaryOrRunEnd(lineStartOffset + firstCharOffset);
+        if (segmentEndOffset == SegmentIterator.DONE) {
+            // There are no text segments containing or after firstCharOffset, so no text segments
+            // in this run overlap the interval.
+            return -1;
+        }
+        int segmentStartOffset = segmentIterator.previousStartBoundaryOrRunStart(segmentEndOffset);
+        float segmentCenter = lineStartPos
+                + (horizontalBounds[2 * (segmentStartOffset - lineStartOffset)]
+                        + horizontalBounds[2 * (segmentEndOffset - lineStartOffset) - 1]) / 2;
+        if ((!isRtl && segmentCenter > right) || (isRtl && segmentCenter < left)) {
+            // The entire interval is to the left (for LTR) of the text segment's center. So the
+            // interval does not contain any text segments within this run.
+            return -1;
+        }
+        if ((!isRtl && segmentCenter >= left) || (isRtl && segmentCenter <= right)) {
+            // The center is within the interval, so return the start offset of this text segment.
+            return segmentStartOffset;
+        }
+
+        // If first text segment's center is not within the interval, try the next text segment.
+        segmentStartOffset = segmentIterator.nextStartBoundaryWithinRunLimits(segmentStartOffset);
+        if (segmentStartOffset == SegmentIterator.DONE
+                || segmentStartOffset == lineStartOffset + runEndOffset) {
+            // No more text segments within this run.
+            return -1;
+        }
+        segmentEndOffset = segmentIterator.nextEndBoundaryOrRunEnd(segmentStartOffset);
+        segmentCenter = lineStartPos
+                + (horizontalBounds[2 * (segmentStartOffset - lineStartOffset)]
+                        + horizontalBounds[2 * (segmentEndOffset - lineStartOffset) - 1]) / 2;
+        // We already know that segmentCenter >= left (for LTR) since the previous word contains the
+        // left point.
+        if ((!isRtl && segmentCenter <= right) || (isRtl && segmentCenter >= left)) {
+            return segmentStartOffset;
+        }
+
+        // If the second text segment is also not within the interval, then this means that the
+        // interval is between the centers of the first and second text segments, so it does not
+        // contain any text segments on this line.
+        return -1;
+    }
+
+    /**
+     * Finds the end character offset of the last text segment inside a horizontal interval within a
+     * directional run.
+     *
+     * @param left left bound of the horizontal interval
+     * @param right right bound of the horizontal interval
+     * @param lineStartOffset start character offset of the line containing this run
+     * @param lineStartPos start position of the line containing this run
+     * @param horizontalBounds array containing the signed horizontal bounds of the characters in
+     *     the line. The left and right bounds of the character at offset i are stored at index (2 *
+     *     i) and index (2 * i + 1). Bounds are relative to {@code lineStartPos}.
+     * @param runStartOffset start offset of the run relative to {@code lineStartOffset}
+     * @param runEndOffset end offset of the run relative to {@code lineStartOffset}
+     * @param runLeft left bound of the run
+     * @param runRight right bound of the run
+     * @param isRtl whether the run is right-to-left
+     * @param segmentIterator iterator for determining the ranges of text to be considered as a text
+     *     segment
+     * @return the end character offset of the last text segment inside the horizontal interval
+     */
+    private static int getEndOffsetForHorizontalIntervalWithinRun(
+            float left, float right,
+            @IntRange(from = 0) int lineStartOffset,
+            @IntRange(from = 0) int lineStartPos,
+            @NonNull float[] horizontalBounds,
+            @IntRange(from = 0) int runStartOffset, @IntRange(from = 0) int runEndOffset,
+            float runLeft, float runRight,
+            boolean isRtl,
+            @NonNull SegmentIterator segmentIterator) {
+        if (runRight < left || runLeft > right) {
+            // The run does not overlap the interval.
+            return -1;
+        }
+
+        // Find the last character in the run whose bounds overlap with the interval.
+        // firstCharOffset is an offset index within the line.
+        int lastCharOffset;
+        if ((!isRtl && right >= runRight) || (isRtl && left <= runLeft)) {
+            lastCharOffset = runEndOffset - 1;
+        } else {
+            int low = runStartOffset;
+            int high = runEndOffset;
+            int guess;
+            while (high - low > 1) {
+                guess = (high + low) / 2;
+                // Left edge of the character at guess
+                float pos = lineStartPos + horizontalBounds[2 * guess];
+                if ((!isRtl && pos > right) || (isRtl && pos < left)) {
+                    high = guess;
+                } else {
+                    low = guess;
+                }
+            }
+            // The interval bound is between the left edge of the character at low and the left edge
+            // of the character at high. For LTR text, this is within the character at low. For RTL
+            // text, this is within the character at high.
+            lastCharOffset = isRtl ? high : low;
+        }
+
+        // Find the last text segment containing this character (or, if no text segment
+        // contains this character, the first text segment before this character). All
+        // following text segments in this run are to the right (for LTR) of the interval.
+        segmentIterator.setRunLimits(
+                lineStartOffset + runStartOffset, lineStartOffset + runEndOffset);
+        // + 1 to allow segmentStartOffset = lineStartOffset + lastCharOffset
+        int segmentStartOffset =
+                segmentIterator.previousStartBoundaryOrRunStart(
+                        lineStartOffset + lastCharOffset + 1);
+        if (segmentStartOffset == SegmentIterator.DONE) {
+            // There are no text segments containing or before lastCharOffset, so no text segments
+            // in this run overlap the interval.
+            return -1;
+        }
+        int segmentEndOffset = segmentIterator.nextEndBoundaryOrRunEnd(segmentStartOffset);
+        float segmentCenter = lineStartPos
+                + (horizontalBounds[2 * (segmentStartOffset - lineStartOffset)]
+                        + horizontalBounds[2 * (segmentEndOffset - lineStartOffset) - 1]) / 2;
+        if ((!isRtl && segmentCenter < left) || (isRtl && segmentCenter > right)) {
+            // The entire interval is to the right (for LTR) of the text segment's center. So the
+            // interval does not contain any text segments within this run.
+            return -1;
+        }
+        if ((!isRtl && segmentCenter <= right) || (isRtl && segmentCenter >= left)) {
+            // The center is within the interval, so return the end offset of this text segment.
+            return segmentEndOffset;
+        }
+
+        // If first text segment's center is not within the interval, try the next text segment.
+        segmentEndOffset = segmentIterator.previousEndBoundaryWithinRunLimits(segmentEndOffset);
+        if (segmentEndOffset == SegmentIterator.DONE
+                || segmentEndOffset == lineStartOffset + runStartOffset) {
+            // No more text segments within this run.
+            return -1;
+        }
+        segmentStartOffset = segmentIterator.previousStartBoundaryOrRunStart(segmentEndOffset);
+        segmentCenter = lineStartPos
+                + (horizontalBounds[2 * (segmentStartOffset - lineStartOffset)]
+                        + horizontalBounds[2 * (segmentEndOffset - lineStartOffset) - 1]) / 2;
+        // We already know that segmentCenter <= right (for LTR) since the following word
+        // contains the right point.
+        if ((!isRtl && segmentCenter >= left) || (isRtl && segmentCenter <= right)) {
+            return segmentEndOffset;
+        }
+
+        // If the second text segment is also not within the interval, then this means that the
+        // interval is between the centers of the first and second text segments, so it does not
+        // contain any text segments on this line.
+        return -1;
+    }
+
+    /**
      * Return the text offset after the last character on the specified line.
      */
     public final int getLineEnd(int line) {
diff --git a/core/java/android/text/SegmentIterator.java b/core/java/android/text/SegmentIterator.java
new file mode 100644
index 0000000..00522e5
--- /dev/null
+++ b/core/java/android/text/SegmentIterator.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+import android.annotation.IntRange;
+
+/**
+ * Finds text segment boundaries within text. Subclasses can implement different types of text
+ * segments. Grapheme clusters and words are examples of possible text segments.
+ *
+ * <p>Granular units may not overlap, so every character belongs to at most one text segment. A
+ * character may belong to no text segments.
+ *
+ * <p>For example, a word level text segment iterator may subdivide the text "Hello, World!" into
+ * four text segments: "Hello", ",", "World", "!". The space character does not belong to any text
+ * segments.
+ *
+ * @hide
+ */
+public abstract class SegmentIterator {
+    public static final int DONE = -1;
+
+    private int mRunStartOffset;
+    private int mRunEndOffset;
+
+    /**
+     * Returns the character offset of the previous text segment start boundary before the specified
+     * character offset, or {@code DONE} if there are none.
+     */
+    public abstract int previousStartBoundary(@IntRange(from = 0) int offset);
+
+    /**
+     * Returns the character offset of the previous text segment end boundary before the specified
+     * character offset, or {@code DONE} if there are none.
+     */
+    public abstract int previousEndBoundary(@IntRange(from = 0) int offset);
+
+    /**
+     * Returns the character offset of the next text segment start boundary after the specified
+     * character offset, or {@code DONE} if there are none.
+     */
+    public abstract int nextStartBoundary(@IntRange(from = 0) int offset);
+
+    /**
+     * Returns the character offset of the next text segment end boundary after the specified
+     * character offset, or {@code DONE} if there are none.
+     */
+    public abstract int nextEndBoundary(@IntRange(from = 0) int offset);
+
+    /**
+     * Sets the start and end of a run which can be used to constrain the scope of the iterator's
+     * search.
+     *
+     * @hide
+     */
+    void setRunLimits(
+            @IntRange(from = 0) int runStartOffset, @IntRange(from = 0) int runEndOffset) {
+        mRunStartOffset = runStartOffset;
+        mRunEndOffset = runEndOffset;
+    }
+
+    /** @hide */
+    int previousStartBoundaryOrRunStart(@IntRange(from = 0) int offset) {
+        int start = previousStartBoundary(offset);
+        if (start == DONE) {
+            return DONE;
+        }
+        return Math.max(start, mRunStartOffset);
+    }
+
+    /** @hide */
+    int previousEndBoundaryWithinRunLimits(@IntRange(from = 0) int offset) {
+        int end = previousEndBoundary(offset);
+        if (end <= mRunStartOffset) {
+            return DONE;
+        }
+        return end;
+    }
+
+    /** @hide */
+    int nextStartBoundaryWithinRunLimits(@IntRange(from = 0) int offset) {
+        int start = nextStartBoundary(offset);
+        if (start >= mRunEndOffset) {
+            return DONE;
+        }
+        return start;
+    }
+
+    /** @hide */
+    int nextEndBoundaryOrRunEnd(@IntRange(from = 0) int offset) {
+        int end = nextEndBoundary(offset);
+        if (end == DONE) {
+            return DONE;
+        }
+        return Math.min(end, mRunEndOffset);
+    }
+}
diff --git a/core/java/android/text/WordSegmentIterator.java b/core/java/android/text/WordSegmentIterator.java
new file mode 100644
index 0000000..1115319
--- /dev/null
+++ b/core/java/android/text/WordSegmentIterator.java
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.icu.text.BreakIterator;
+import android.text.method.WordIterator;
+
+/**
+ * Implementation of {@code SegmentIterator} using words as the text segment. Word boundaries are
+ * found using {@code WordIterator}. Whitespace characters are excluded, so they are not included in
+ * any text segments.
+ *
+ * @hide
+ */
+public class WordSegmentIterator extends SegmentIterator {
+    private final CharSequence mText;
+    private final WordIterator mWordIterator;
+
+    public WordSegmentIterator(@NonNull CharSequence text, @NonNull WordIterator wordIterator) {
+        mText = text;
+        mWordIterator = wordIterator;
+    }
+
+    @Override
+    public int previousStartBoundary(@IntRange(from = 0) int offset) {
+        int boundary = offset;
+        do {
+            boundary = mWordIterator.prevBoundary(boundary);
+            if (boundary == BreakIterator.DONE) {
+                return DONE;
+            }
+        } while (Character.isWhitespace(mText.charAt(boundary)));
+        return boundary;
+    }
+
+    @Override
+    public int previousEndBoundary(@IntRange(from = 0) int offset) {
+        int boundary = offset;
+        do {
+            boundary = mWordIterator.prevBoundary(boundary);
+            if (boundary == BreakIterator.DONE || boundary == 0) {
+                return DONE;
+            }
+        } while (Character.isWhitespace(mText.charAt(boundary - 1)));
+        return boundary;
+    }
+
+    @Override
+    public int nextStartBoundary(@IntRange(from = 0) int offset) {
+        int boundary = offset;
+        do {
+            boundary = mWordIterator.nextBoundary(boundary);
+            if (boundary == BreakIterator.DONE || boundary == mText.length()) {
+                return DONE;
+            }
+        } while (Character.isWhitespace(mText.charAt(boundary)));
+        return boundary;
+    }
+
+    @Override
+    public int nextEndBoundary(@IntRange(from = 0) int offset) {
+        int boundary = offset;
+        do {
+            boundary = mWordIterator.nextBoundary(boundary);
+            if (boundary == BreakIterator.DONE) {
+                return DONE;
+            }
+        } while (Character.isWhitespace(mText.charAt(boundary - 1)));
+        return boundary;
+    }
+}
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/ArrayMap.java b/core/java/android/util/ArrayMap.java
index c0bc991..155f508 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -23,6 +23,7 @@
 
 import libcore.util.EmptyArray;
 
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
 import java.util.Map;
@@ -231,7 +232,7 @@
                             array[0] = array[1] = null;
                             mTwiceBaseCacheSize--;
                             if (DEBUG) {
-                                Log.d(TAG, "Retrieving 2x cache " + mHashes
+                                Log.d(TAG, "Retrieving 2x cache " + Arrays.toString(mHashes)
                                         + " now have " + mTwiceBaseCacheSize + " entries");
                             }
                             return;
@@ -258,7 +259,7 @@
                             array[0] = array[1] = null;
                             mBaseCacheSize--;
                             if (DEBUG) {
-                                Log.d(TAG, "Retrieving 1x cache " + mHashes
+                                Log.d(TAG, "Retrieving 1x cache " + Arrays.toString(mHashes)
                                         + " now have " + mBaseCacheSize + " entries");
                             }
                             return;
@@ -295,8 +296,10 @@
                     }
                     mTwiceBaseCache = array;
                     mTwiceBaseCacheSize++;
-                    if (DEBUG) Log.d(TAG, "Storing 2x cache " + array
-                            + " now have " + mTwiceBaseCacheSize + " entries");
+                    if (DEBUG) {
+                        Log.d(TAG, "Storing 2x cache " + Arrays.toString(array)
+                                + " now have " + mTwiceBaseCacheSize + " entries");
+                    }
                 }
             }
         } else if (hashes.length == BASE_SIZE) {
@@ -309,8 +312,10 @@
                     }
                     mBaseCache = array;
                     mBaseCacheSize++;
-                    if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
-                            + " now have " + mBaseCacheSize + " entries");
+                    if (DEBUG) {
+                        Log.d(TAG, "Storing 1x cache " + Arrays.toString(array)
+                                + " now have " + mBaseCacheSize + " entries");
+                    }
                 }
             }
         }
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index b5c75b9..73114e2 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -23,6 +23,7 @@
 import libcore.util.EmptyArray;
 
 import java.lang.reflect.Array;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
@@ -194,8 +195,8 @@
                             array[0] = array[1] = null;
                             sTwiceBaseCacheSize--;
                             if (DEBUG) {
-                                Log.d(TAG, "Retrieving 2x cache " + mHashes + " now have "
-                                        + sTwiceBaseCacheSize + " entries");
+                                Log.d(TAG, "Retrieving 2x cache " + Arrays.toString(mHashes)
+                                        + " now have " + sTwiceBaseCacheSize + " entries");
                             }
                             return;
                         }
@@ -221,8 +222,8 @@
                             array[0] = array[1] = null;
                             sBaseCacheSize--;
                             if (DEBUG) {
-                                Log.d(TAG, "Retrieving 1x cache " + mHashes + " now have "
-                                        + sBaseCacheSize + " entries");
+                                Log.d(TAG, "Retrieving 1x cache " + Arrays.toString(mHashes)
+                                        + " now have " + sBaseCacheSize + " entries");
                             }
                             return;
                         }
@@ -259,8 +260,8 @@
                     sTwiceBaseCache = array;
                     sTwiceBaseCacheSize++;
                     if (DEBUG) {
-                        Log.d(TAG, "Storing 2x cache " + array + " now have " + sTwiceBaseCacheSize
-                                + " entries");
+                        Log.d(TAG, "Storing 2x cache " + Arrays.toString(array) + " now have "
+                                + sTwiceBaseCacheSize + " entries");
                     }
                 }
             }
@@ -275,7 +276,7 @@
                     sBaseCache = array;
                     sBaseCacheSize++;
                     if (DEBUG) {
-                        Log.d(TAG, "Storing 1x cache " + array + " now have "
+                        Log.d(TAG, "Storing 1x cache " + Arrays.toString(array) + " now have "
                                 + sBaseCacheSize + " entries");
                     }
                 }
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index bca100a..20f01ae 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -68,6 +68,12 @@
     public static final String SETTINGS_APP_LOCALE_OPT_IN_ENABLED =
             "settings_app_locale_opt_in_enabled";
 
+    /**
+     * Launch the Volume panel in SystemUI.
+     * @hide
+     */
+    public static final String SETTINGS_VOLUME_PANEL_IN_SYSTEMUI =
+            "settings_volume_panel_in_systemui";
 
     /** @hide */
     public static final String SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS =
@@ -110,6 +116,12 @@
      */
     public static final String SETTINGS_NEW_KEYBOARD_UI = "settings_new_keyboard_ui";
 
+    /**
+     * Enable the new pages which is implemented with SPA.
+     * @hide
+     */
+    public static final String SETTINGS_ENABLE_SPA = "settings_enable_spa";
+
     private static final Map<String, String> DEFAULT_FLAGS;
 
     static {
@@ -134,6 +146,7 @@
         DEFAULT_FLAGS.put("settings_search_always_expand", "true");
         DEFAULT_FLAGS.put(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE, "false");
         DEFAULT_FLAGS.put(SETTINGS_APP_LOCALE_OPT_IN_ENABLED, "true");
+        DEFAULT_FLAGS.put(SETTINGS_VOLUME_PANEL_IN_SYSTEMUI, "false");
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
         DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true");
         DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
@@ -141,6 +154,7 @@
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_CLEAR_CALLING, "false");
         DEFAULT_FLAGS.put(SETTINGS_ACCESSIBILITY_SIMPLE_CURSOR, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_UI, "false");
+        DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "false");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/android/util/proto/ProtoInputStream.java b/core/java/android/util/proto/ProtoInputStream.java
index 9789b10..9a15cd5 100644
--- a/core/java/android/util/proto/ProtoInputStream.java
+++ b/core/java/android/util/proto/ProtoInputStream.java
@@ -21,6 +21,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Class to read to a protobuf stream.
@@ -968,26 +970,17 @@
     public String dumpDebugData() {
         StringBuilder sb = new StringBuilder();
 
-        sb.append("\nmFieldNumber : 0x" + Integer.toHexString(mFieldNumber));
-        sb.append("\nmWireType : 0x" + Integer.toHexString(mWireType));
-        sb.append("\nmState : 0x" + Integer.toHexString(mState));
-        sb.append("\nmDiscardedBytes : 0x" + Integer.toHexString(mDiscardedBytes));
-        sb.append("\nmOffset : 0x" + Integer.toHexString(mOffset));
-        sb.append("\nmExpectedObjectTokenStack : ");
-        if (mExpectedObjectTokenStack == null) {
-            sb.append("null");
-        } else {
-            sb.append(mExpectedObjectTokenStack);
-        }
-        sb.append("\nmDepth : 0x" + Integer.toHexString(mDepth));
-        sb.append("\nmBuffer : ");
-        if (mBuffer == null) {
-            sb.append("null");
-        } else {
-            sb.append(mBuffer);
-        }
-        sb.append("\nmBufferSize : 0x" + Integer.toHexString(mBufferSize));
-        sb.append("\nmEnd : 0x" + Integer.toHexString(mEnd));
+        sb.append("\nmFieldNumber : 0x").append(Integer.toHexString(mFieldNumber));
+        sb.append("\nmWireType : 0x").append(Integer.toHexString(mWireType));
+        sb.append("\nmState : 0x").append(Integer.toHexString(mState));
+        sb.append("\nmDiscardedBytes : 0x").append(Integer.toHexString(mDiscardedBytes));
+        sb.append("\nmOffset : 0x").append(Integer.toHexString(mOffset));
+        sb.append("\nmExpectedObjectTokenStack : ")
+                .append(Objects.toString(mExpectedObjectTokenStack));
+        sb.append("\nmDepth : 0x").append(Integer.toHexString(mDepth));
+        sb.append("\nmBuffer : ").append(Arrays.toString(mBuffer));
+        sb.append("\nmBufferSize : 0x").append(Integer.toHexString(mBufferSize));
+        sb.append("\nmEnd : 0x").append(Integer.toHexString(mEnd));
 
         return sb.toString();
     }
diff --git a/core/java/android/util/proto/ProtoUtils.java b/core/java/android/util/proto/ProtoUtils.java
index 8464d2d..58d9913 100644
--- a/core/java/android/util/proto/ProtoUtils.java
+++ b/core/java/android/util/proto/ProtoUtils.java
@@ -20,6 +20,7 @@
 import android.util.Duration;
 
 import java.io.IOException;
+import java.util.Arrays;
 
 /**
  * This class contains a list of helper functions to write common proto in
@@ -91,27 +92,27 @@
         final int wireType = proto.getWireType();
         long fieldConstant;
 
-        sb.append("Offset : 0x" + Integer.toHexString(proto.getOffset()));
-        sb.append("\nField Number : 0x" + Integer.toHexString(proto.getFieldNumber()));
+        sb.append("Offset : 0x").append(Integer.toHexString(proto.getOffset()));
+        sb.append("\nField Number : 0x").append(Integer.toHexString(proto.getFieldNumber()));
         sb.append("\nWire Type : ");
         switch (wireType) {
             case ProtoStream.WIRE_TYPE_VARINT:
-                sb.append("varint");
                 fieldConstant = ProtoStream.makeFieldId(fieldNumber,
                         ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT64);
-                sb.append("\nField Value : 0x" + Long.toHexString(proto.readLong(fieldConstant)));
+                sb.append("varint\nField Value : 0x");
+                sb.append(Long.toHexString(proto.readLong(fieldConstant)));
                 break;
             case ProtoStream.WIRE_TYPE_FIXED64:
-                sb.append("fixed64");
                 fieldConstant = ProtoStream.makeFieldId(fieldNumber,
                         ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64);
-                sb.append("\nField Value : 0x" + Long.toHexString(proto.readLong(fieldConstant)));
+                sb.append("fixed64\nField Value : 0x");
+                sb.append(Long.toHexString(proto.readLong(fieldConstant)));
                 break;
             case ProtoStream.WIRE_TYPE_LENGTH_DELIMITED:
-                sb.append("length delimited");
                 fieldConstant = ProtoStream.makeFieldId(fieldNumber,
                         ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES);
-                sb.append("\nField Bytes : " + proto.readBytes(fieldConstant));
+                sb.append("length delimited\nField Bytes : ");
+                sb.append(Arrays.toString(proto.readBytes(fieldConstant)));
                 break;
             case ProtoStream.WIRE_TYPE_START_GROUP:
                 sb.append("start group");
@@ -120,13 +121,13 @@
                 sb.append("end group");
                 break;
             case ProtoStream.WIRE_TYPE_FIXED32:
-                sb.append("fixed32");
                 fieldConstant = ProtoStream.makeFieldId(fieldNumber,
                         ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32);
-                sb.append("\nField Value : 0x" + Integer.toHexString(proto.readInt(fieldConstant)));
+                sb.append("fixed32\nField Value : 0x");
+                sb.append(Integer.toHexString(proto.readInt(fieldConstant)));
                 break;
             default:
-                sb.append("unknown(" + proto.getWireType() + ")");
+                sb.append("unknown(").append(proto.getWireType()).append(")");
         }
         return sb.toString();
     }
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/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 380c104..9e25a3e 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -116,8 +116,10 @@
      * and be issued to the display subsystem.
      * </p>
      * <p>
-     * Equal to the sum of the values of all other time-valued metric
-     * identifiers.
+     * The total duration is the difference in time between when the frame
+     * began and when it ended. This value may not be exactly equal to the
+     * sum of the values of all other time-valued metric identifiers because
+     * some stages may happen concurrently.
      * </p>
      */
     public static final int TOTAL_DURATION = 8;
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index 57ba7e9..f9bb880 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 (mInLongPress || mInContextClick) {
+                if ((mCurrentDownEvent == null) || mInLongPress || mInContextClick) {
                     break;
                 }
 
@@ -736,6 +736,9 @@
                 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/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 14691b3..a1ece92 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -116,9 +116,6 @@
                     // The motion event is not from a stylus event, ignore it.
                     return false;
                 }
-                if (!mImm.isStylusHandwritingAvailable()) {
-                    return false;
-                }
                 mState = new State(motionEvent);
                 break;
             case MotionEvent.ACTION_POINTER_UP:
@@ -280,6 +277,13 @@
         mHandwritingAreasTracker.updateHandwritingAreaForView(view);
     }
 
+    private static boolean shouldTriggerStylusHandwritingForView(@NonNull View view) {
+        if (!view.isAutoHandwritingEnabled()) {
+            return false;
+        }
+        return view.isStylusHandwritingAvailable();
+    }
+
     /**
      * Given the location of the stylus event, return the best candidate view to initialize
      * handwriting mode.
@@ -296,9 +300,10 @@
         // whether the connectedView's boundary contains the initial stylus position. If true,
         // directly return the connectedView.
         final View connectedView = getConnectedView();
-        if (connectedView != null && connectedView.isAutoHandwritingEnabled()) {
+        if (connectedView != null) {
             Rect handwritingArea = getViewHandwritingArea(connectedView);
-            if (isInHandwritingArea(handwritingArea, x, y, connectedView)) {
+            if (isInHandwritingArea(handwritingArea, x, y, connectedView)
+                    && shouldTriggerStylusHandwritingForView(connectedView)) {
                 final float distance = distance(handwritingArea, x, y);
                 if (distance == 0f) return connectedView;
 
@@ -313,10 +318,12 @@
         for (HandwritableViewInfo viewInfo : handwritableViewInfos) {
             final View view = viewInfo.getView();
             final Rect handwritingArea = viewInfo.getHandwritingArea();
-            if (!isInHandwritingArea(handwritingArea, x, y, view)) continue;
+            if (!isInHandwritingArea(handwritingArea, x, y, view)
+                    || !shouldTriggerStylusHandwritingForView(view)) {
+                continue;
+            }
 
             final float distance = distance(handwritingArea, x, y);
-
             if (distance == 0f) return view;
             if (distance < minDistance) {
                 minDistance = distance;
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..38911e0 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.
@@ -1040,6 +1174,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/InsetsState.java b/core/java/android/view/InsetsState.java
index 45d28da..9f426a1 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -351,20 +351,6 @@
         return insets;
     }
 
-    // TODO: Remove this once the task bar is treated as navigation bar.
-    public Insets calculateInsetsWithInternalTypes(Rect frame, @InternalInsetsType int[] types,
-            boolean ignoreVisibility) {
-        Insets insets = Insets.NONE;
-        for (int i = types.length - 1; i >= 0; i--) {
-            InsetsSource source = mSources[types[i]];
-            if (source == null) {
-                continue;
-            }
-            insets = Insets.max(source.calculateInsets(frame, ignoreVisibility), insets);
-        }
-        return insets;
-    }
-
     public Insets calculateInsets(Rect frame, @InsetsType int types,
             InsetsVisibilities overrideVisibilities) {
         Insets insets = Insets.NONE;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index c3a638c..6c238e5 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -866,13 +866,19 @@
     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;
 
    /**
      * 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_KEYBOARD_BACKLIGHT_TOGGLE;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -2019,6 +2025,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/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 0bed342..ea00125 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1509,6 +1509,13 @@
      */
     public static final int TOOL_TYPE_PALM = 5;
 
+    /** @hide */
+    @Retention(SOURCE)
+    @IntDef(prefix = { "TOOL_TYPE_" }, value = {
+            TOOL_TYPE_UNKNOWN, TOOL_TYPE_FINGER, TOOL_TYPE_STYLUS, TOOL_TYPE_MOUSE,
+            TOOL_TYPE_ERASER, TOOL_TYPE_PALM})
+    public @interface ToolType {};
+
     // NOTE: If you add a new tool type here you must also add it to:
     //  native/include/android/input.h
 
@@ -2422,7 +2429,7 @@
      * @see #TOOL_TYPE_STYLUS
      * @see #TOOL_TYPE_MOUSE
      */
-    public final int getToolType(int pointerIndex) {
+    public @ToolType int getToolType(int pointerIndex) {
         return nativeGetToolType(mNativePtr, pointerIndex);
     }
 
@@ -3868,7 +3875,7 @@
      * @return The symbolic name of the specified tool type.
      * @hide
      */
-    public static String toolTypeToString(int toolType) {
+    public static String toolTypeToString(@ToolType int toolType) {
         String symbolicName = TOOL_TYPE_SYMBOLIC_NAMES.get(toolType);
         return symbolicName != null ? symbolicName : Integer.toString(toolType);
     }
@@ -4361,7 +4368,7 @@
          *
          * @see MotionEvent#getToolType(int)
          */
-        public int toolType;
+        public @ToolType int toolType;
 
         /**
          * Resets the pointer properties to their initial values.
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6b21bed..2208f89 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -985,6 +985,8 @@
      *
      * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or
      * <code>changeFrameRateStrategy</code> are invalid.
+     *
+     * @see #clearFrameRate()
      */
     public void setFrameRate(@FloatRange(from = 0.0) float frameRate,
             @FrameRateCompatibility int compatibility,
@@ -996,7 +998,33 @@
             if (error == -EINVAL) {
                 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
             } else if (error != 0) {
-                throw new RuntimeException("Failed to set frame rate on Surface");
+                throw new RuntimeException("Failed to set frame rate on Surface. Native error: "
+                        + error);
+            }
+        }
+    }
+
+    /**
+     * Clears the frame rate which was set for this surface.
+     *
+     * <p>This is equivalent to calling {@link #setFrameRate(float, int, int)} using {@code 0} for
+     * {@code frameRate}.
+     * <p>Note that this only has an effect for surfaces presented on the display. If this
+     * surface is consumed by something other than the system compositor, e.g. a media
+     * codec, this call has no effect.</p>
+     *
+     * @see #setFrameRate(float, int, int)
+     */
+    public void clearFrameRate() {
+        synchronized (mLock) {
+            checkNotReleasedLocked();
+            // The values FRAME_RATE_COMPATIBILITY_DEFAULT and CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS
+            // are ignored because the value of frameRate is 0
+            int error = nativeSetFrameRate(mNativeObject, 0,
+                    FRAME_RATE_COMPATIBILITY_DEFAULT, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+            if (error != 0) {
+                throw new RuntimeException("Failed to clear the frame rate on Surface. Native error"
+                        + ": " + error);
             }
         }
     }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e0f02d6..aef38eb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1943,7 +1943,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(supportedDisplayModes, activeDisplayModeId, activeDisplayModeId,
+            return Objects.hash(Arrays.hashCode(supportedDisplayModes), activeDisplayModeId,
                     activeColorMode, hdrCapabilities);
         }
     }
@@ -3612,6 +3612,8 @@
          *                                black screen for a second or two. This parameter is
          *                                ignored when <code>frameRate</code> is 0.
          * @return This transaction object.
+         *
+         * @see #clearFrameRate(SurfaceControl)
          */
         @NonNull
         public Transaction setFrameRate(@NonNull SurfaceControl sc,
@@ -3625,6 +3627,30 @@
         }
 
         /**
+         * Clears the frame rate which was set for the surface {@link SurfaceControl}.
+         *
+         * <p>This is equivalent to calling {@link #setFrameRate(SurfaceControl, float, int, int)}
+         * using {@code 0} for {@code frameRate}.
+         * <p>
+         * Note that this only has an effect for surfaces presented on the display. If this
+         * surface is consumed by something other than the system compositor, e.g. a media
+         * codec, this call has no effect.
+         *
+         * @param sc The SurfaceControl to clear the frame rate of.
+         * @return This transaction object.
+         *
+         * @see #setFrameRate(SurfaceControl, float, int)
+         */
+        @NonNull
+        public Transaction clearFrameRate(@NonNull SurfaceControl sc) {
+            checkPreconditions(sc);
+            nativeSetFrameRate(mNativeObject, sc.mNativeObject, 0.0f,
+                    Surface.FRAME_RATE_COMPATIBILITY_DEFAULT,
+                    Surface.CHANGE_FRAME_RATE_ALWAYS);
+            return this;
+        }
+
+        /**
          * Sets the default frame rate compatibility for the surface {@link SurfaceControl}
          *
          * @param sc The SurfaceControl to specify the frame rate of.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b6c92e3..7acf319 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1622,8 +1622,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 996dee0..8fee4db 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;
@@ -151,6 +152,7 @@
 import android.view.displayhash.DisplayHashResultCallback;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
 import android.view.inspector.InspectableProperty;
 import android.view.inspector.InspectableProperty.EnumEntry;
 import android.view.inspector.InspectableProperty.FlagEntry;
@@ -12888,7 +12890,6 @@
         if (mViewTranslationCallback != null) {
             mViewTranslationCallback.onClearTranslation(this);
         }
-        clearViewTranslationCallback();
         clearViewTranslationResponse();
         if (hasTranslationTransientState()) {
             setHasTransientState(false);
@@ -27545,6 +27546,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.
@@ -27569,6 +27575,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;
@@ -31800,6 +31811,15 @@
     }
 
     /**
+     * Return whether the stylus handwriting is available for this View.
+     * @hide
+     */
+    public boolean isStylusHandwritingAvailable() {
+        return getContext().getSystemService(InputMethodManager.class)
+                .isStylusHandwritingAvailable();
+    }
+
+    /**
      * Collects a {@link ViewTranslationRequest} which represents the content to be translated in
      * the view.
      *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e8179cf..074cbe5 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -286,7 +286,7 @@
      * @hide
      */
     public static final boolean LOCAL_LAYOUT =
-            SystemProperties.getBoolean("persist.debug.local_layout", true);
+            SystemProperties.getBoolean("persist.debug.local_layout", false);
 
     /**
      * Set this system property to true to force the view hierarchy to render
@@ -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
@@ -4751,25 +4753,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 +4766,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);
             }
 
@@ -8242,6 +8226,7 @@
                 mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
             }
             mInvSizeCompatScale = 1f / mTmpFrames.sizeCompatScale;
+            CompatibilityInfo.applyOverrideScaleIfNeeded(mPendingMergedConfiguration);
             mInsetsController.onStateChanged(mTempInsets);
             mInsetsController.onControlsChanged(mTempControls);
 
@@ -9575,7 +9560,7 @@
 
     /**
      * Return the connection ID for the {@link AccessibilityInteractionController} of this instance.
-     * @see AccessibilityNodeInfo#makeQueryableFromAppProcess(View)
+     * @see AccessibilityNodeInfo#setQueryFromAppProcessEnabled
      */
     public int getDirectAccessibilityConnectionId() {
         return mAccessibilityInteractionConnectionManager.ensureDirectConnection();
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/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6ae59bf..1f33806 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -84,7 +84,7 @@
  * <p>
  * Once an accessibility node info is delivered to an accessibility service it is
  * made immutable and calling a state mutation method generates an error. See
- * {@link #makeQueryableFromAppProcess(View)} if you would like to inspect the
+ * {@link #setQueryFromAppProcessEnabled} if you would like to inspect the
  * node tree from the app process for testing or debugging tools.
  * </p>
  * <p>
@@ -1175,7 +1175,7 @@
      * @return The child node.
      *
      * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before
-     *                               calling {@link #makeQueryableFromAppProcess(View)}.
+     *                               calling {@link #setQueryFromAppProcessEnabled}.
      */
     public AccessibilityNodeInfo getChild(int index) {
         return getChild(index, FLAG_PREFETCH_DESCENDANTS_HYBRID);
@@ -1190,7 +1190,7 @@
      * @return The child node.
      *
      * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before
-     *                               calling {@link #makeQueryableFromAppProcess(View)}.
+     *                               calling {@link #setQueryFromAppProcessEnabled}.
      *
      * @see AccessibilityNodeInfo#getParent(int) for a description of prefetching.
      */
@@ -1914,7 +1914,7 @@
      * @return The parent.
      *
      * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before
-     *                               calling {@link #makeQueryableFromAppProcess(View)}.
+     *                               calling {@link #setQueryFromAppProcessEnabled}.
      */
     public AccessibilityNodeInfo getParent() {
         enforceSealed();
@@ -1943,7 +1943,7 @@
      * @return The parent.
      *
      * @throws IllegalStateException If called outside of an {@link AccessibilityService} and before
-     *                               calling {@link #makeQueryableFromAppProcess(View)}.
+     *                               calling {@link #setQueryFromAppProcessEnabled}.
      *
      * @see #FLAG_PREFETCH_ANCESTORS
      * @see #FLAG_PREFETCH_DESCENDANTS_BREADTH_FIRST
@@ -3669,30 +3669,47 @@
      * {@link AccessibilityNodeInfo} tree and perform accessibility actions on nodes.
      *
      * <p>
-     * This is intended for short-lived inspections from testing or debugging tools in the app
-     * process. After calling this method, all nodes linked to this node (children, ancestors, etc.)
-     * are also queryable. Operations on this node tree will only succeed as long as the associated
-     * view hierarchy remains attached to a window.
-     * </p>
-     *
-     * <p>
-     * Calling this method more than once on the same node is a no-op; if you wish to inspect a
-     * different view hierarchy then create a new node from any view in that hierarchy and call this
-     * method on that node.
-     * </p>
-     *
-     * <p>
      * Testing or debugging tools should create this {@link AccessibilityNodeInfo} node using
      * {@link View#createAccessibilityNodeInfo()} or {@link AccessibilityNodeProvider} and call this
      * method, then navigate and interact with the node tree by calling methods on the node.
+     * Calling this method more than once on the same node is a no-op. After calling this method,
+     * all nodes linked to this node (children, ancestors, etc.) are also queryable.
+     * </p>
+     *
+     * <p>
+     * Here "query" refers to the following node operations:
+     * <li>check properties of this node (example: {@link #isScrollable()})</li>
+     * <li>find and query children (example: {@link #getChild(int)})</li>
+     * <li>find and query the parent (example: {@link #getParent()})</li>
+     * <li>find focus (examples: {@link #findFocus(int)}, {@link #focusSearch(int)})</li>
+     * <li>find and query other nodes (example: {@link #findAccessibilityNodeInfosByText(String)},
+     * {@link #findAccessibilityNodeInfosByViewId(String)})</li>
+     * <li>perform actions (example: {@link #performAction(int)})</li>
+     * </p>
+     *
+     * <p>
+     * This is intended for short-lived inspections from testing or debugging tools in the app
+     * process, as operations on this node tree will only succeed as long as the associated
+     * view hierarchy remains attached to a window. {@link AccessibilityNodeInfo} objects can
+     * quickly become out of sync with their corresponding {@link View} objects; if you wish to
+     * inspect a changed or different view hierarchy then create a new node from any view in that
+     * hierarchy and call this method on that new node, instead of disabling & re-enabling the
+     * connection on the previous node.
      * </p>
      *
      * @param view The view that generated this node, or any view in the same view-root hierarchy.
+     * @param enabled Whether to enable (true) or disable (false) querying from the app process.
      * @throws IllegalStateException If called from an {@link AccessibilityService}, or if provided
      *                               a {@link View} that is not attached to a window.
      */
-    public void makeQueryableFromAppProcess(@NonNull View view) {
+    public void setQueryFromAppProcessEnabled(@NonNull View view, boolean enabled) {
         enforceNotSealed();
+
+        if (!enabled) {
+            setConnectionId(UNDEFINED_CONNECTION_ID);
+            return;
+        }
+
         if (mConnectionId != UNDEFINED_CONNECTION_ID) {
             return;
         }
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index a170891..a8ed96e 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -27,7 +27,10 @@
 import android.text.TextUtils;
 import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -119,6 +122,13 @@
     private final float[] mMatrixValues;
 
     /**
+     * A list of visible line bounds stored in a float array. This array is divided into segment of
+     * four where each element in the segment represents left, top, right respectively and bottom
+     * of the line bounds.
+     */
+    private final float[] mVisibleLineBounds;
+
+    /**
      * Flag for {@link #getInsertionMarkerFlags()} and {@link #getCharacterBoundsFlags(int)}: the
      * insertion marker or character bounds have at least one visible region.
      */
@@ -150,6 +160,7 @@
         mCharacterBoundsArray = source.readParcelable(SparseRectFArray.class.getClassLoader(), android.view.inputmethod.SparseRectFArray.class);
         mEditorBoundsInfo = source.readTypedObject(EditorBoundsInfo.CREATOR);
         mMatrixValues = source.createFloatArray();
+        mVisibleLineBounds = source.createFloatArray();
     }
 
     /**
@@ -173,6 +184,7 @@
         dest.writeParcelable(mCharacterBoundsArray, flags);
         dest.writeTypedObject(mEditorBoundsInfo, flags);
         dest.writeFloatArray(mMatrixValues);
+        dest.writeFloatArray(mVisibleLineBounds);
     }
 
     @Override
@@ -229,6 +241,10 @@
             return false;
         }
 
+        if (!Arrays.equals(mVisibleLineBounds, that.mVisibleLineBounds)) {
+            return false;
+        }
+
         // Following fields are (partially) covered by hashCode().
 
         if (mComposingTextStart != that.mComposingTextStart
@@ -262,6 +278,7 @@
                 + " mInsertionMarkerBottom=" + mInsertionMarkerBottom
                 + " mCharacterBoundsArray=" + Objects.toString(mCharacterBoundsArray)
                 + " mEditorBoundsInfo=" + mEditorBoundsInfo
+                + " mVisibleLineBounds=" + getVisibleLineBounds()
                 + " mMatrix=" + Arrays.toString(mMatrixValues)
                 + "}";
     }
@@ -270,6 +287,7 @@
      * Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe.
      */
     public static final class Builder {
+        private static final int LINE_BOUNDS_INITIAL_SIZE = 4;
         private int mSelectionStart = -1;
         private int mSelectionEnd = -1;
         private int mComposingTextStart = -1;
@@ -283,6 +301,8 @@
         private EditorBoundsInfo mEditorBoundsInfo = null;
         private float[] mMatrixValues = null;
         private boolean mMatrixInitialized = false;
+        private float[] mVisibleLineBounds = new float[LINE_BOUNDS_INITIAL_SIZE * 4];
+        private int mVisibleLineBoundsCount = 0;
 
         /**
          * Sets the text range of the selection. Calling this can be skipped if there is no
@@ -396,6 +416,49 @@
         }
 
         /**
+         * Add the bounds of a visible text line of the current editor.
+         *
+         * The line bounds should not include the vertical space between lines or the horizontal
+         * space before and after a line.
+         * It's preferable if the line bounds are added in the logical order, so that IME can
+         * process them easily.
+         *
+         * @param left the left bound of the left-most character in the line
+         * @param top the top bound of the top-most character in the line
+         * @param right the right bound of the right-most character in the line
+         * @param bottom the bottom bound of the bottom-most character in the line
+         *
+         * @see CursorAnchorInfo#getVisibleLineBounds()
+         * @see #clearVisibleLineBounds()
+         */
+        @NonNull
+        public Builder addVisibleLineBounds(float left, float top, float right, float bottom) {
+            if (mVisibleLineBounds.length <= mVisibleLineBoundsCount + 4) {
+                mVisibleLineBounds =
+                        Arrays.copyOf(mVisibleLineBounds, (mVisibleLineBoundsCount + 4) * 2);
+            }
+            mVisibleLineBounds[mVisibleLineBoundsCount++] = left;
+            mVisibleLineBounds[mVisibleLineBoundsCount++] = top;
+            mVisibleLineBounds[mVisibleLineBoundsCount++] = right;
+            mVisibleLineBounds[mVisibleLineBoundsCount++] = bottom;
+            return this;
+        }
+
+        /**
+         * Clear the visible text line bounds previously added to this {@link Builder}.
+         *
+         * @see #addVisibleLineBounds(float, float, float, float)
+         */
+        @NonNull
+        public Builder clearVisibleLineBounds() {
+            // Since mVisibleLineBounds is copied in build(), we only need to reset
+            // mVisibleLineBoundsCount to 0. And mVisibleLineBounds will be reused for better
+            // performance.
+            mVisibleLineBoundsCount = 0;
+            return this;
+        }
+
+        /**
          * @return {@link CursorAnchorInfo} using parameters in this {@link Builder}.
          * @throws IllegalArgumentException if one or more positional parameters are specified but
          * the coordinate transformation matrix is not provided via {@link #setMatrix(Matrix)}.
@@ -406,7 +469,10 @@
                 // parameter is specified.
                 final boolean hasCharacterBounds = (mCharacterBoundsArrayBuilder != null
                         && !mCharacterBoundsArrayBuilder.isEmpty());
+                final boolean hasVisibleLineBounds = (mVisibleLineBounds != null
+                        && mVisibleLineBoundsCount > 0);
                 if (hasCharacterBounds
+                        || hasVisibleLineBounds
                         || !Float.isNaN(mInsertionMarkerHorizontal)
                         || !Float.isNaN(mInsertionMarkerTop)
                         || !Float.isNaN(mInsertionMarkerBaseline)
@@ -437,6 +503,7 @@
                 mCharacterBoundsArrayBuilder.reset();
             }
             mEditorBoundsInfo = null;
+            clearVisibleLineBounds();
         }
     }
 
@@ -456,7 +523,8 @@
                 builder.mComposingTextStart, builder.mComposingText, builder.mInsertionMarkerFlags,
                 builder.mInsertionMarkerHorizontal, builder.mInsertionMarkerTop,
                 builder.mInsertionMarkerBaseline, builder.mInsertionMarkerBottom,
-                characterBoundsArray, builder.mEditorBoundsInfo, matrixValues);
+                characterBoundsArray, builder.mEditorBoundsInfo, matrixValues,
+                Arrays.copyOf(builder.mVisibleLineBounds, builder.mVisibleLineBoundsCount));
     }
 
     private CursorAnchorInfo(int selectionStart, int selectionEnd, int composingTextStart,
@@ -465,7 +533,7 @@
             float insertionMarkerBaseline, float insertionMarkerBottom,
             @Nullable SparseRectFArray characterBoundsArray,
             @Nullable EditorBoundsInfo editorBoundsInfo,
-            @NonNull float[] matrixValues) {
+            @NonNull float[] matrixValues, @Nullable float[] visibleLineBounds) {
         mSelectionStart = selectionStart;
         mSelectionEnd = selectionEnd;
         mComposingTextStart = composingTextStart;
@@ -478,6 +546,7 @@
         mCharacterBoundsArray = characterBoundsArray;
         mEditorBoundsInfo = editorBoundsInfo;
         mMatrixValues = matrixValues;
+        mVisibleLineBounds = visibleLineBounds;
 
         // To keep hash function simple, we only use some complex objects for hash.
         int hashCode = Objects.hashCode(mComposingText);
@@ -503,7 +572,8 @@
                 original.mInsertionMarkerFlags, original.mInsertionMarkerHorizontal,
                 original.mInsertionMarkerTop, original.mInsertionMarkerBaseline,
                 original.mInsertionMarkerBottom, original.mCharacterBoundsArray,
-                original.mEditorBoundsInfo, computeMatrixValues(parentMatrix, original));
+                original.mEditorBoundsInfo, computeMatrixValues(parentMatrix, original),
+                original.mVisibleLineBounds);
     }
 
     /**
@@ -637,6 +707,30 @@
     }
 
     /**
+     * Returns the list of {@link RectF}s indicating the locations of the visible line bounds in
+     * the editor.
+     * @return the visible line bounds in the local coordinates as a list of {@link RectF}.
+     *
+     * @see Builder#addVisibleLineBounds(float, float, float, float)
+     */
+    @NonNull
+    public List<RectF> getVisibleLineBounds() {
+        if (mVisibleLineBounds == null) {
+            return Collections.emptyList();
+        }
+        final List<RectF> result = new ArrayList<>(mVisibleLineBounds.length / 4);
+        for (int index = 0; index < mVisibleLineBounds.length;) {
+            final RectF rectF = new RectF(
+                    mVisibleLineBounds[index++],
+                    mVisibleLineBounds[index++],
+                    mVisibleLineBounds[index++],
+                    mVisibleLineBounds[index++]);
+            result.add(rectF);
+        }
+        return result;
+    }
+
+    /**
      * Returns {@link EditorBoundsInfo} for the current editor, or {@code null} if IME is not
      * subscribed with {@link InputConnection#CURSOR_UPDATE_FILTER_EDITOR_BOUNDS}
      * or {@link InputConnection#CURSOR_UPDATE_MONITOR}.
diff --git a/core/java/android/view/inputmethod/DeleteGesture.java b/core/java/android/view/inputmethod/DeleteGesture.java
index 1395578..9fadabf 100644
--- a/core/java/android/view/inputmethod/DeleteGesture.java
+++ b/core/java/android/view/inputmethod/DeleteGesture.java
@@ -64,7 +64,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 +144,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/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 5515548..c3b32c9 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -42,6 +42,7 @@
 import android.util.Printer;
 import android.util.proto.ProtoOutputStream;
 import android.view.MotionEvent;
+import android.view.MotionEvent.ToolType;
 import android.view.View;
 import android.view.autofill.AutofillId;
 
@@ -560,6 +561,10 @@
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_INSERT;
             } else if (gesture.equals(DeleteGesture.class)) {
                 supportedTypes |= HandwritingGesture.GESTURE_TYPE_DELETE;
+            } 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);
             }
@@ -594,6 +599,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;
     }
 
@@ -639,8 +652,7 @@
      * Initial {@link MotionEvent#ACTION_UP} tool type {@link MotionEvent#getToolType(int)} that
      * was used to focus this editor.
      */
-    private int mInitialToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
-
+    private @ToolType int mInitialToolType = MotionEvent.TOOL_TYPE_UNKNOWN;
 
     /**
      * Editors may use this method to provide initial input text to IMEs. As the surrounding text
@@ -1022,7 +1034,7 @@
      * @see InputMethodService#onUpdateEditorToolType(int)
      * @return toolType {@link MotionEvent#getToolType(int)}.
      */
-    public int getInitialToolType() {
+    public @ToolType int getInitialToolType() {
         return mInitialToolType;
     }
 
@@ -1034,7 +1046,7 @@
      * @see MotionEvent#getToolType(int)
      * @see InputMethodService#onUpdateEditorToolType(int)
      */
-    public void setInitialToolType(int toolType) {
+    public void setInitialToolType(@ToolType int toolType) {
         mInitialToolType = toolType;
     }
 
diff --git a/core/java/android/view/inputmethod/HandwritingGesture.java b/core/java/android/view/inputmethod/HandwritingGesture.java
index a659333..494aaaa 100644
--- a/core/java/android/view/inputmethod/HandwritingGesture.java
+++ b/core/java/android/view/inputmethod/HandwritingGesture.java
@@ -99,15 +99,23 @@
      */
     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;
+
     /**
      * 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_INSERT,
+            GESTURE_TYPE_DELETE,
+            GESTURE_TYPE_REMOVE_SPACE,
+            GESTURE_TYPE_JOIN_OR_SPLIT})
     @Retention(RetentionPolicy.SOURCE)
     @interface GestureType{}
 
@@ -121,7 +129,9 @@
     @IntDef(flag = true, prefix = {"GESTURE_TYPE_"}, value = {
             GESTURE_TYPE_SELECT,
             GESTURE_TYPE_INSERT,
-            GESTURE_TYPE_DELETE})
+            GESTURE_TYPE_DELETE,
+            GESTURE_TYPE_REMOVE_SPACE,
+            GESTURE_TYPE_JOIN_OR_SPLIT})
     @Retention(RetentionPolicy.SOURCE)
     public @interface GestureTypeFlags{}
 
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 068d28e..2f834c9 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1070,8 +1070,9 @@
      * </p>
      * <p>
      * Note by default all of {@link #CURSOR_UPDATE_FILTER_EDITOR_BOUNDS},
-     * {@link #CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS} and
-     * {@link #CURSOR_UPDATE_FILTER_INSERTION_MARKER} are included but specifying them can
+     * {@link #CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS},
+     * {@link #CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS} and
+     * {@link #CURSOR_UPDATE_FILTER_INSERTION_MARKER}, are included but specifying them can
      * filter-out others.
      * It can be CPU intensive to include all, filtering specific info is recommended.
      * </p>
@@ -1085,6 +1086,7 @@
      * monitoring, call {@link InputConnection#requestCursorUpdates(int)} again with this flag off.
      * <p>
      * This flag can be used together with filters: {@link #CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS},
+     * {@link #CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS},
      * {@link #CURSOR_UPDATE_FILTER_INSERTION_MARKER} and update flags
      * {@link #CURSOR_UPDATE_IMMEDIATE} and {@link #CURSOR_UPDATE_MONITOR}.
      * </p>
@@ -1099,6 +1101,7 @@
      * monitoring, call {@link InputConnection#requestCursorUpdates(int)} again with this flag off.
      * <p>
      * This flag can be combined with other filters: {@link #CURSOR_UPDATE_FILTER_EDITOR_BOUNDS},
+     * {@link #CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS},
      * {@link #CURSOR_UPDATE_FILTER_INSERTION_MARKER} and update flags
      * {@link #CURSOR_UPDATE_IMMEDIATE} and {@link #CURSOR_UPDATE_MONITOR}.
      * </p>
@@ -1114,6 +1117,7 @@
      * with this flag off.
      * <p>
      * This flag can be combined with other filters: {@link #CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS},
+     * {@link #CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS},
      * {@link #CURSOR_UPDATE_FILTER_EDITOR_BOUNDS} and update flags {@link #CURSOR_UPDATE_IMMEDIATE}
      * and {@link #CURSOR_UPDATE_MONITOR}.
      * </p>
@@ -1121,6 +1125,22 @@
     int CURSOR_UPDATE_FILTER_INSERTION_MARKER = 1 << 4;
 
     /**
+     * The editor is requested to call
+     * {@link InputMethodManager#updateCursorAnchorInfo(android.view.View, CursorAnchorInfo)}
+     * with new visible line bounds {@link CursorAnchorInfo#getVisibleLineBounds()} whenever
+     * cursor/anchor position is changed, the editor or its parent is scrolled or the line bounds
+     * changed due to text updates. To disable monitoring, call
+     * {@link InputConnection#requestCursorUpdates(int)} again with this flag off.
+     * <p>
+     * This flag can be combined with other filters: {@link #CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS},
+     * {@link #CURSOR_UPDATE_FILTER_EDITOR_BOUNDS}, {@link #CURSOR_UPDATE_FILTER_INSERTION_MARKER}
+     * and update flags {@link #CURSOR_UPDATE_IMMEDIATE}
+     * and {@link #CURSOR_UPDATE_MONITOR}.
+     * </p>
+     */
+    int CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS = 1 << 5;
+
+    /**
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
@@ -1133,8 +1153,8 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(value = {CURSOR_UPDATE_FILTER_EDITOR_BOUNDS, CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS,
-            CURSOR_UPDATE_FILTER_INSERTION_MARKER}, flag = true,
-            prefix = { "CURSOR_UPDATE_FILTER_" })
+            CURSOR_UPDATE_FILTER_INSERTION_MARKER, CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS},
+            flag = true, prefix = { "CURSOR_UPDATE_FILTER_" })
     @interface CursorUpdateFilter{}
 
     /**
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 6049613..0c7c163 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -439,17 +439,20 @@
     /**
      * True if this input method client is active, initially false.
      */
+    @GuardedBy("mH")
     private boolean mActive = false;
 
     /**
      * {@code true} if next {@link ImeFocusController#onPostWindowFocus} needs to
      * restart input.
      */
+    @GuardedBy("mH")
     private boolean mRestartOnNextWindowFocus = true;
 
     /**
      * As reported by IME through InputConnection.
      */
+    @GuardedBy("mH")
     private boolean mFullscreenMode;
 
     // -----------------------------------------------------------
@@ -460,46 +463,70 @@
      */
     @GuardedBy("mH")
     ViewRootImpl mCurRootView;
+
     /**
      * This is set when we are in the process of connecting, to determine
      * when we have actually finished.
      */
+    @GuardedBy("mH")
     private boolean mServedConnecting;
+
     /**
      * This is non-null when we have connected the served view; it holds
      * the attributes that were last retrieved from the served view and given
      * to the input connection.
      */
+    @GuardedBy("mH")
     private EditorInfo mCurrentEditorInfo;
+
+    @GuardedBy("mH")
+    @Nullable
+    private ViewFocusParameterInfo mPreviousViewFocusParameters;
+
     /**
      * The InputConnection that was last retrieved from the served view.
      */
+    @GuardedBy("mH")
     private RemoteInputConnectionImpl mServedInputConnection;
+
     /**
      * The completions that were last provided by the served view.
      */
+    @GuardedBy("mH")
     private CompletionInfo[] mCompletions;
 
     // Cursor position on the screen.
+    @GuardedBy("mH")
     @UnsupportedAppUsage
     Rect mTmpCursorRect = new Rect();
+
+    @GuardedBy("mH")
     @UnsupportedAppUsage
     Rect mCursorRect = new Rect();
+
+    @GuardedBy("mH")
     private int mCursorSelStart;
+    @GuardedBy("mH")
     private int mCursorSelEnd;
+    @GuardedBy("mH")
     private int mCursorCandStart;
+    @GuardedBy("mH")
     private int mCursorCandEnd;
+    @GuardedBy("mH")
     private int mInitialSelStart;
+    @GuardedBy("mH")
     private int mInitialSelEnd;
 
     /**
      * Handler for {@link RemoteInputConnectionImpl#getInputConnection()}.
      */
+    @GuardedBy("mH")
     private Handler mServedInputConnectionHandler;
 
     /**
      * The instance that has previously been sent to the input method.
      */
+    @GuardedBy("mH")
     private CursorAnchorInfo mCursorAnchorInfo = null;
 
     /**
@@ -522,6 +549,7 @@
      * @deprecated New code should use {@code mCurBindState.mImeId}.
      */
     @Deprecated
+    @GuardedBy("mH")
     @UnsupportedAppUsage
     String mCurId;
 
@@ -551,7 +579,9 @@
     private final SparseArray<IAccessibilityInputMethodSessionInvoker>
             mAccessibilityInputMethodSession = new SparseArray<>();
 
+    @GuardedBy("mH")
     private InputChannel mCurChannel;
+    @GuardedBy("mH")
     private ImeInputEventSender mCurSender;
 
     private static final int REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE = 0x0;
@@ -561,14 +591,18 @@
      * @deprecated This is kept for {@link UnsupportedAppUsage}.  Must not be used.
      */
     @Deprecated
+    @GuardedBy("mH")
     private int mRequestUpdateCursorAnchorInfoMonitorMode = REQUEST_UPDATE_CURSOR_ANCHOR_INFO_NONE;
 
     /**
      * Applies the IME visibility and listens for other state changes.
      */
+    @GuardedBy("mH")
     private ImeInsetsSourceConsumer mImeInsetsConsumer;
 
+    @GuardedBy("mH")
     private final Pool<PendingEvent> mPendingEventPool = new SimplePool<>(20);
+    @GuardedBy("mH")
     private final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
 
     private final DelegateImpl mDelegate = new DelegateImpl();
@@ -660,26 +694,6 @@
 
     private final class DelegateImpl implements
             ImeFocusController.InputMethodManagerDelegate {
-        @GuardedBy("mH")
-        @Nullable
-        private ViewFocusParameterInfo mPreviousViewFocusParameters;
-
-        @GuardedBy("mH")
-        private void updatePreviousViewFocusParametersLocked(
-                @Nullable EditorInfo currentEditorInfo,
-                @StartInputFlags int startInputFlags,
-                @StartInputReason int startInputReason,
-                @SoftInputModeFlags int softInputMode,
-                int windowFlags) {
-            mPreviousViewFocusParameters = new ViewFocusParameterInfo(currentEditorInfo,
-                    startInputFlags, startInputReason, softInputMode, windowFlags);
-        }
-
-        @GuardedBy("mH")
-        private void clearStateLocked() {
-            mPreviousViewFocusParameters = null;
-        }
-
         /**
          * Used by {@link ImeFocusController} to start input connection.
          */
@@ -800,8 +814,10 @@
          */
         @Override
         public void finishComposingText() {
-            if (mServedInputConnection != null) {
-                mServedInputConnection.finishComposingTextFromImm();
+            synchronized (mH) {
+                if (mServedInputConnection != null) {
+                    mServedInputConnection.finishComposingTextFromImm();
+                }
             }
         }
 
@@ -833,11 +849,13 @@
          */
         @Override
         public boolean isRestartOnNextWindowFocus(boolean reset) {
-            final boolean result = mRestartOnNextWindowFocus;
-            if (reset) {
-                mRestartOnNextWindowFocus = false;
+            synchronized (mH) {
+                final boolean result = mRestartOnNextWindowFocus;
+                if (reset) {
+                    mRestartOnNextWindowFocus = false;
+                }
+                return result;
             }
-            return result;
         }
 
         /**
@@ -878,21 +896,25 @@
         return mDelegate.hasActiveConnection(view);
     }
 
+    @GuardedBy("mH")
     private View getServedViewLocked() {
         return mCurRootView != null ? mCurRootView.getImeFocusController().getServedView() : null;
     }
 
+    @GuardedBy("mH")
     private View getNextServedViewLocked() {
         return mCurRootView != null ? mCurRootView.getImeFocusController().getNextServedView()
                 : null;
     }
 
+    @GuardedBy("mH")
     private void setServedViewLocked(View view) {
         if (mCurRootView != null) {
             mCurRootView.getImeFocusController().setServedView(view);
         }
     }
 
+    @GuardedBy("mH")
     private void setNextServedViewLocked(View view) {
         if (mCurRootView != null) {
             mCurRootView.getImeFocusController().setNextServedView(view);
@@ -911,6 +933,7 @@
     /**
      * Returns {@code true} when the given view has been served by Input Method.
      */
+    @GuardedBy("mH")
     private boolean hasServedByInputMethodLocked(View view) {
         final View servedView = getServedViewLocked();
         return (servedView == view
@@ -1729,7 +1752,7 @@
     @GuardedBy("mH")
     private void clearConnectionLocked() {
         mCurrentEditorInfo = null;
-        mDelegate.clearStateLocked();
+        mPreviousViewFocusParameters = null;
         if (mServedInputConnection != null) {
             mServedInputConnection.deactivate();
             mServedInputConnection = null;
@@ -1748,7 +1771,7 @@
         if (getServedViewLocked() != null) {
             if (DEBUG) {
                 Log.v(TAG, "FINISH INPUT: mServedView="
-                        + dumpViewInfo(getServedViewLocked()));
+                        + InputMethodDebug.dumpViewInfo(getServedViewLocked()));
             }
             setServedViewLocked(null);
             mCompletions = null;
@@ -2281,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) {
@@ -2352,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
@@ -2414,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));
             }
 
@@ -2424,10 +2447,10 @@
                     && previouslyServedConnection == null
                     && ic == null
                     && isSwitchingBetweenEquivalentNonEditableViews(
-                            mDelegate.mPreviousViewFocusParameters, startInputFlags,
+                            mPreviousViewFocusParameters, startInputFlags,
                             startInputReason, softInputMode, windowFlags);
-            updatePreviousViewFocusParametersLocked(mCurrentEditorInfo, startInputFlags,
-                    startInputReason, softInputMode, windowFlags);
+            mPreviousViewFocusParameters = new ViewFocusParameterInfo(mCurrentEditorInfo,
+                    startInputFlags, startInputReason, softInputMode, windowFlags);
             if (canSkip) {
                 if (DEBUG) {
                     Log.d(TAG, "Not calling IMMS due to switching between non-editable views.");
@@ -2499,29 +2522,6 @@
     }
 
     /**
-     * This method exists only so that the
-     * <a href="https://errorprone.info/bugpattern/GuardedBy">errorprone</a> false positive warning
-     * can be suppressed without granting a blanket exception to the {@link #startInputInner}
-     * method.
-     * <p>
-     * The warning in question implies that the access to the
-     * {@link DelegateImpl#updatePreviousViewFocusParametersLocked} method should be guarded by
-     * {@code InputMethodManager.this.mH}, but instead {@code mDelegate.mH} is held in the caller.
-     * In this case errorprone fails to realize that it is the same object.
-     */
-    @GuardedBy("mH")
-    @SuppressWarnings("GuardedBy")
-    private void updatePreviousViewFocusParametersLocked(
-            @Nullable EditorInfo currentEditorInfo,
-            @StartInputFlags int startInputFlags,
-            @StartInputReason int startInputReason,
-            @SoftInputModeFlags int softInputMode,
-            int windowFlags) {
-        mDelegate.updatePreviousViewFocusParametersLocked(currentEditorInfo, startInputFlags,
-                startInputReason, softInputMode, windowFlags);
-    }
-
-    /**
      * @return {@code true} when we are switching focus between two non-editable views
      * so that we can avoid calling {@link IInputMethodManager#startInputOrWindowGainedFocus}.
      */
@@ -3192,6 +3192,7 @@
     }
 
     // Must be called on the main looper
+    @GuardedBy("mH")
     private int sendInputEventOnMainLooperLocked(PendingEvent p) {
         if (mCurChannel != null) {
             if (mCurSender == null) {
@@ -3256,6 +3257,7 @@
         }
     }
 
+    @GuardedBy("mH")
     private void flushPendingEventsLocked() {
         mH.removeMessages(MSG_FLUSH_INPUT_EVENT);
 
@@ -3268,6 +3270,7 @@
         }
     }
 
+    @GuardedBy("mH")
     private PendingEvent obtainPendingEventLocked(InputEvent event, Object token,
             String inputMethodId, FinishedInputEventCallback callback, Handler handler) {
         PendingEvent p = mPendingEventPool.acquire();
@@ -3282,6 +3285,7 @@
         return p;
     }
 
+    @GuardedBy("mH")
     private void recyclePendingEventLocked(PendingEvent p) {
         p.recycle();
         mPendingEventPool.release(p);
@@ -3314,6 +3318,7 @@
         mServiceInvoker.showInputMethodPickerFromSystem(mClient, mode, displayId);
     }
 
+    @GuardedBy("mH")
     private void showInputMethodPickerLocked() {
         mServiceInvoker.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
     }
@@ -3769,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}.
@@ -3848,6 +3836,7 @@
         }
     }
 
+    @GuardedBy("mH")
     private void forAccessibilitySessionsLocked(
             Consumer<IAccessibilityInputMethodSessionInvoker> consumer) {
         for (int i = 0; i < mAccessibilityInputMethodSession.size(); i++) {
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/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
similarity index 75%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
index 88e227b..e339b55 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/core/java/android/view/inputmethod/JoinOrSplitGesture.aidl
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package android.view.inputmethod;
 
-import javax.inject.Qualifier
-
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+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/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
similarity index 75%
rename from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
rename to core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
index 88e227b..7aab528 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/core/java/android/view/inputmethod/RemoveSpaceGesture.aidl
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package android.view.inputmethod;
 
-import javax.inject.Qualifier
-
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+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..2f02e66 100644
--- a/core/java/android/view/inputmethod/SelectGesture.java
+++ b/core/java/android/view/inputmethod/SelectGesture.java
@@ -63,8 +63,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 +125,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 +143,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/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 6825f03..cebaa76 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -226,8 +226,6 @@
     final UndoInputFilter mUndoInputFilter = new UndoInputFilter(this);
     boolean mAllowUndo = true;
 
-    private int mLastInputSource = InputDevice.SOURCE_UNKNOWN;
-
     private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     // Cursor Controllers.
@@ -1735,8 +1733,6 @@
     public void onTouchEvent(MotionEvent event) {
         final boolean filterOutEvent = shouldFilterOutTouchEvent(event);
 
-        mLastInputSource = event.getSource();
-
         mLastButtonState = event.getButtonState();
         if (filterOutEvent) {
             if (event.getActionMasked() == MotionEvent.ACTION_UP) {
@@ -1789,7 +1785,7 @@
     }
 
     private void showFloatingToolbar() {
-        if (mTextActionMode != null && showUIForTouchScreen()) {
+        if (mTextActionMode != null && mTextView.showUIForTouchScreen()) {
             // Delay "show" so it doesn't interfere with click confirmations
             // or double-clicks that could "dismiss" the floating toolbar.
             int delay = ViewConfiguration.getDoubleTapTimeout();
@@ -1870,7 +1866,7 @@
                     ? getSelectionController() : getInsertionController();
             if (cursorController != null && !cursorController.isActive()
                     && !cursorController.isCursorBeingModified()
-                    && showUIForTouchScreen()) {
+                    && mTextView.showUIForTouchScreen()) {
                 cursorController.show();
             }
         }
@@ -2521,7 +2517,7 @@
             return false;
         }
 
-        if (!showUIForTouchScreen()) {
+        if (!mTextView.showUIForTouchScreen()) {
             return false;
         }
 
@@ -2677,7 +2673,7 @@
                     mTextView.postDelayed(mShowSuggestionRunnable,
                             ViewConfiguration.getDoubleTapTimeout());
                 } else if (hasInsertionController()) {
-                    if (shouldInsertCursor && showUIForTouchScreen()) {
+                    if (shouldInsertCursor && mTextView.showUIForTouchScreen()) {
                         getInsertionController().show();
                     } else {
                         getInsertionController().hide();
@@ -4621,12 +4617,16 @@
                     (filter & InputConnection.CURSOR_UPDATE_FILTER_CHARACTER_BOUNDS) != 0;
             boolean includeInsertionMarker =
                     (filter & InputConnection.CURSOR_UPDATE_FILTER_INSERTION_MARKER) != 0;
+            boolean includeVisibleLineBounds =
+                    (filter & InputConnection.CURSOR_UPDATE_FILTER_VISIBLE_LINE_BOUNDS) != 0;
             boolean includeAll =
-                    (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker);
+                    (!includeEditorBounds && !includeCharacterBounds && !includeInsertionMarker
+                    && !includeVisibleLineBounds);
 
             includeEditorBounds |= includeAll;
             includeCharacterBounds |= includeAll;
             includeInsertionMarker |= includeAll;
+            includeVisibleLineBounds |= includeAll;
 
             final CursorAnchorInfo.Builder builder = mSelectionInfoBuilder;
             builder.reset();
@@ -4655,7 +4655,7 @@
                 builder.setEditorBoundsInfo(editorBoundsInfo);
             }
 
-            if (includeCharacterBounds || includeInsertionMarker) {
+            if (includeCharacterBounds || includeInsertionMarker || includeVisibleLineBounds) {
                 final float viewportToContentHorizontalOffset =
                         mTextView.viewportToContentHorizontalOffset();
                 final float viewportToContentVerticalOffset =
@@ -4718,6 +4718,32 @@
                                 insertionMarkerFlags);
                     }
                 }
+
+                if (includeVisibleLineBounds) {
+                    Rect visibleRect = new Rect();
+                    if (mTextView.getLocalVisibleRect(visibleRect)) {
+                        final float visibleTop =
+                                visibleRect.top + viewportToContentVerticalOffset;
+                        final float visibleBottom =
+                                visibleRect.bottom + viewportToContentVerticalOffset;
+                        final int firstLine =
+                                layout.getLineForVertical((int) Math.floor(visibleTop));
+                        final int lastLine =
+                                layout.getLineForVertical((int) Math.ceil(visibleBottom));
+
+                        for (int line = firstLine; line <= lastLine; ++line) {
+                            final float left = layout.getLineLeft(line)
+                                    + viewportToContentHorizontalOffset;
+                            final float top = layout.getLineTop(line)
+                                    + viewportToContentVerticalOffset;
+                            final float right = layout.getLineRight(line)
+                                    + viewportToContentHorizontalOffset;
+                            final float bottom = layout.getLineBottom(line)
+                                    + viewportToContentVerticalOffset;
+                            builder.addVisibleLineBounds(left, top, right, bottom);
+                        }
+                    }
+                }
             }
 
             imm.updateCursorAnchorInfo(mTextView, builder.build());
@@ -5408,7 +5434,7 @@
             final boolean shouldShow = checkForTransforms() /*check not rotated and compute scale*/
                     && !tooLargeTextForMagnifier()
                     && obtainMagnifierShowCoordinates(event, showPosInView)
-                    && showUIForTouchScreen();
+                    && mTextView.showUIForTouchScreen();
             if (shouldShow) {
                 // Make the cursor visible and stop blinking.
                 mRenderCursorRegardlessTiming = true;
@@ -6354,16 +6380,6 @@
         }
     }
 
-    /**
-     * Returns true when need to show UIs, e.g. floating toolbar, etc, for finger based interaction.
-     *
-     * @return true if UIs need to show for finger interaciton. false if UIs are not necessary.
-     */
-    public boolean showUIForTouchScreen() {
-        return (mLastInputSource & InputDevice.SOURCE_TOUCHSCREEN)
-                == InputDevice.SOURCE_TOUCHSCREEN;
-    }
-
     /** Controller for the insertion cursor. */
     @VisibleForTesting
     public class InsertionPointCursorController implements CursorController {
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4ccd77b..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(),
@@ -301,7 +304,7 @@
             final SelectionModifierCursorController controller = mEditor.getSelectionController();
             if (controller != null
                     && (mTextView.isTextSelectable() || mTextView.isTextEditable())) {
-                if (mEditor.showUIForTouchScreen()) {
+                if (mTextView.showUIForTouchScreen()) {
                     controller.show();
                 } else {
                     controller.hide();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 6a572c5..68b902f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -72,6 +72,7 @@
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetricsInt;
 import android.graphics.Path;
+import android.graphics.PointF;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -98,12 +99,14 @@
 import android.text.DynamicLayout;
 import android.text.Editable;
 import android.text.GetChars;
+import android.text.GraphemeClusterSegmentIterator;
 import android.text.GraphicsOperations;
 import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Layout;
 import android.text.ParcelableSpan;
 import android.text.PrecomputedText;
+import android.text.SegmentIterator;
 import android.text.Selection;
 import android.text.SpanWatcher;
 import android.text.Spannable;
@@ -117,6 +120,7 @@
 import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.text.TextWatcher;
+import android.text.WordSegmentIterator;
 import android.text.method.AllCapsTransformationMethod;
 import android.text.method.ArrowKeyMovementMethod;
 import android.text.method.DateKeyListener;
@@ -183,11 +187,15 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.DeleteGesture;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.HandwritingGesture;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.SelectGesture;
 import android.view.inspector.InspectableProperty;
 import android.view.inspector.InspectableProperty.EnumEntry;
 import android.view.inspector.InspectableProperty.FlagEntry;
@@ -965,6 +973,11 @@
     private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN;
 
     /**
+     * The last input source on this TextView.
+     */
+    private int mLastInputSource = InputDevice.SOURCE_UNKNOWN;
+
+    /**
      * The TextView does not auto-size text (default).
      */
     public static final int AUTO_SIZE_TEXT_TYPE_NONE = 0;
@@ -7631,7 +7644,7 @@
         createEditorIfNeeded();
         mEditor.setError(error, icon);
         notifyViewAccessibilityStateChangedIfNeeded(
-                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_INVALID);
     }
 
     @Override
@@ -9072,6 +9085,12 @@
                 outAttrs.initialCapsMode = ic.getCursorCapsMode(getInputType());
                 outAttrs.setInitialSurroundingText(mText);
                 outAttrs.contentMimeTypes = getReceiveContentMimeTypes();
+
+                ArrayList<Class<? extends HandwritingGesture>> gestures = new ArrayList<>();
+                gestures.add(SelectGesture.class);
+                gestures.add(DeleteGesture.class);
+                gestures.add(InsertGesture.class);
+                outAttrs.setSupportedHandwritingGestures(gestures);
                 return ic;
             }
         }
@@ -9283,6 +9302,84 @@
     }
 
     /** @hide */
+    public int performHandwritingSelectGesture(@NonNull SelectGesture gesture) {
+        int[] range = getRangeForRect(gesture.getSelectionArea(), gesture.getGranularity());
+        if (range == null) {
+            return handleGestureFailure(gesture);
+        }
+        Selection.setSelection(getEditableText(), range[0], range[1]);
+        mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
+        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+    }
+
+    /** @hide */
+    public int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture) {
+        int[] range = getRangeForRect(gesture.getDeletionArea(), gesture.getGranularity());
+        if (range == null) {
+            return handleGestureFailure(gesture);
+        }
+        getEditableText().delete(range[0], range[1]);
+        Selection.setSelection(getEditableText(), range[0]);
+        // TODO(b/243983058): Delete extra spaces.
+        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+    }
+
+    /** @hide */
+    public int performHandwritingInsertGesture(@NonNull InsertGesture gesture) {
+        PointF point = gesture.getInsertionPoint();
+        // The coordinates provided are screen coordinates - transform to content coordinates.
+        int[] screenToViewport = getLocationOnScreen();
+        point.offset(
+                -(screenToViewport[0] + viewportToContentHorizontalOffset()),
+                -(screenToViewport[1] + viewportToContentVerticalOffset()));
+
+        int line = mLayout.getLineForVertical((int) point.y);
+        if (point.y < mLayout.getLineTop(line)
+                || point.y > mLayout.getLineBottomWithoutSpacing(line)) {
+            return handleGestureFailure(gesture);
+        }
+        if (point.x < mLayout.getLineLeft(line) || point.x > mLayout.getLineRight(line)) {
+            return handleGestureFailure(gesture);
+        }
+        int offset = mLayout.getOffsetForHorizontal(line, point.x);
+        String textToInsert = gesture.getTextToInsert();
+        getEditableText().insert(offset, textToInsert);
+        Selection.setSelection(getEditableText(), offset + textToInsert.length());
+        // TODO(b/243980426): Insert extra spaces if necessary.
+        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+    }
+
+    private int handleGestureFailure(HandwritingGesture gesture) {
+        if (!TextUtils.isEmpty(gesture.getFallbackText())) {
+            getEditableText()
+                    .replace(getSelectionStart(), getSelectionEnd(), gesture.getFallbackText());
+            return InputConnection.HANDWRITING_GESTURE_RESULT_FALLBACK;
+        }
+        return InputConnection.HANDWRITING_GESTURE_RESULT_FAILED;
+    }
+
+    @Nullable
+    private int[] getRangeForRect(@NonNull RectF area, int granularity) {
+        // The coordinates provided are screen coordinates - transform to content coordinates.
+        int[] screenToViewport = getLocationOnScreen();
+        area = new RectF(area);
+        area.offset(
+                -(screenToViewport[0] + viewportToContentHorizontalOffset()),
+                -(screenToViewport[1] + viewportToContentVerticalOffset()));
+
+        SegmentIterator segmentIterator;
+        if (granularity == HandwritingGesture.GRANULARITY_WORD) {
+            WordIterator wordIterator = getWordIterator();
+            wordIterator.setCharSequence(mText, 0, mText.length());
+            segmentIterator = new WordSegmentIterator(mText, wordIterator);
+        } else {
+            segmentIterator = new GraphemeClusterSegmentIterator(mText, mTextPaint);
+        }
+
+        return mLayout.getRangeForRect(area, segmentIterator);
+    }
+
+    /** @hide */
     @VisibleForTesting
     @UnsupportedAppUsage
     public void nullLayouts() {
@@ -11480,6 +11577,7 @@
                     MotionEvent.actionToString(event.getActionMasked()),
                     event.getX(), event.getY());
         }
+        mLastInputSource = event.getSource();
         final int action = event.getActionMasked();
         if (mEditor != null) {
             if (!isFromPrimePointer(event, false)) {
@@ -11569,6 +11667,17 @@
     }
 
     /**
+     * Returns true when need to show UIs, e.g. floating toolbar, etc, for finger based interaction.
+     *
+     * @return true if UIs need to show for finger interaciton. false if UIs are not necessary.
+     * @hide
+     */
+    public final boolean showUIForTouchScreen() {
+        return (mLastInputSource & InputDevice.SOURCE_TOUCHSCREEN)
+                == InputDevice.SOURCE_TOUCHSCREEN;
+    }
+
+    /**
      * The fill dialog UI is a more conspicuous and efficient interface than dropdown UI.
      * If autofill suggestions are available when the user clicks on a field that supports filling
      * the dialog UI, Autofill will pop up a fill dialog. The dialog will take up a larger area
@@ -11847,6 +11956,11 @@
                         return onTextContextMenuItem(ID_PASTE);
                     }
                     break;
+                case KeyEvent.KEYCODE_Y:
+                    if (canRedo()) {
+                        return onTextContextMenuItem(ID_REDO);
+                    }
+                    break;
             }
         } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
             // Handle Ctrl-Shift shortcuts.
@@ -11935,6 +12049,17 @@
         }
     }
 
+    /** @hide */
+    @Override
+    public boolean isStylusHandwritingAvailable() {
+        if (mTextOperationUser == null) {
+            return super.isStylusHandwritingAvailable();
+        }
+        final int userId = mTextOperationUser.getIdentifier();
+        final InputMethodManager imm = getInputMethodManager();
+        return imm.isStylusHandwritingAvailableAsUser(userId);
+    }
+
     @Nullable
     final TextServicesManager getTextServicesManagerForUser() {
         return getServiceManagerForUser("android", TextServicesManager.class);
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index 884ca77..3250dd8 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -57,6 +57,12 @@
      * Notifies the server that the organizer has finished handling the given transaction. The
      * server should apply the given {@link WindowContainerTransaction} for the necessary changes.
      */
-    void onTransactionHandled(in ITaskFragmentOrganizer organizer, in IBinder transactionToken,
-        in WindowContainerTransaction wct);
+    void onTransactionHandled(in IBinder transactionToken, in WindowContainerTransaction wct,
+        int transitionType, boolean shouldApplyIndependently);
+
+    /**
+     * Requests the server to apply the given {@link WindowContainerTransaction}.
+     */
+    void applyTransaction(in WindowContainerTransaction wct, int transitionType,
+        boolean shouldApplyIndependently);
 }
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index 40bffde..8df6541 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -16,23 +16,24 @@
 
 package android.window;
 
-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.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.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;
 
 import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
-import android.content.Intent;
-import android.content.res.Configuration;
+import android.app.WindowConfiguration;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.view.RemoteAnimationDefinition;
+import android.view.WindowManager;
 
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -46,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";
 
@@ -160,171 +158,118 @@
      *                          {@link #onTransactionReady(TaskFragmentTransaction)}
      * @param wct               {@link WindowContainerTransaction} that the server should apply for
      *                          update of the transaction.
-     * @see com.android.server.wm.WindowOrganizerController#enforceTaskPermission for permission
-     * requirement.
+     * @param transitionType    {@link WindowManager.TransitionType} if it needs to start a
+     *                          transition.
+     * @param shouldApplyIndependently  If {@code true}, the {@code wct} will request a new
+     *                                  transition, which will be queued until the sync engine is
+     *                                  free if there is any other active sync. If {@code false},
+     *                                  the {@code wct} will be directly applied to the active sync.
+     * @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission
+     * for permission enforcement.
      * @hide
      */
     public void onTransactionHandled(@NonNull IBinder transactionToken,
-            @NonNull WindowContainerTransaction wct) {
+            @NonNull WindowContainerTransaction wct,
+            @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
         wct.setTaskFragmentOrganizer(mInterface);
         try {
-            getController().onTransactionHandled(mInterface, transactionToken, wct);
+            getController().onTransactionHandled(transactionToken, wct, transitionType,
+                    shouldApplyIndependently);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Called when a TaskFragment is created and organized by this organizer.
+     * Routes to {@link ITaskFragmentOrganizerController#applyTransaction} instead of
+     * {@link IWindowOrganizerController#applyTransaction} for the different transition options.
      *
-     * @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.
+     * @see #applyTransaction(WindowContainerTransaction, int, boolean)
      */
-    public void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
-            @NonNull TaskFragmentInfo taskFragmentInfo) {}
+    @Override
+    public void applyTransaction(@NonNull WindowContainerTransaction wct) {
+        // TODO(b/207070762) doing so to keep CTS compatibility. Remove in the next release.
+        applyTransaction(wct, getTransitionType(wct), false /* shouldApplyIndependently */);
+    }
 
     /**
-     * Called when the status of an organized TaskFragment is changed.
+     * Requests the server to apply the given {@link WindowContainerTransaction}.
      *
-     * @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.
+     * @param wct   {@link WindowContainerTransaction} to apply.
+     * @param transitionType    {@link WindowManager.TransitionType} if it needs to start a
+     *                          transition.
+     * @param shouldApplyIndependently  If {@code true}, the {@code wct} will request a new
+     *                                  transition, which will be queued until the sync engine is
+     *                                  free if there is any other active sync. If {@code false},
+     *                                  the {@code wct} will be directly applied to the active sync.
+     * @see com.android.server.wm.WindowOrganizerController#enforceTaskFragmentOrganizerPermission
+     * for permission enforcement.
+     * @hide
      */
-    public void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
-            @NonNull TaskFragmentInfo taskFragmentInfo) {}
+    public void applyTransaction(@NonNull WindowContainerTransaction wct,
+            @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
+        if (wct.isEmpty()) {
+            return;
+        }
+        wct.setTaskFragmentOrganizer(mInterface);
+        try {
+            getController().applyTransaction(wct, transitionType, shouldApplyIndependently);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 
     /**
-     * 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.
+     * Gets the default {@link WindowManager.TransitionType} based on the requested
+     * {@link WindowContainerTransaction}.
+     * @hide
      */
-    public void onTaskFragmentVanished(@NonNull WindowContainerTransaction wct,
-            @NonNull TaskFragmentInfo taskFragmentInfo) {}
+    // TODO(b/207070762): let Extensions to set the transition type instead.
+    @WindowManager.TransitionType
+    public static int getTransitionType(@NonNull WindowContainerTransaction wct) {
+        if (wct.isEmpty()) {
+            return TRANSIT_NONE;
+        }
+        for (WindowContainerTransaction.Change change : wct.getChanges().values()) {
+            if ((change.getWindowSetMask() & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0) {
+                // Treat as TRANSIT_CHANGE when there is TaskFragment resizing.
+                return TRANSIT_CHANGE;
+            }
+        }
+        boolean containsCreatingTaskFragment = false;
+        boolean containsDeleteTaskFragment = false;
+        final List<WindowContainerTransaction.HierarchyOp> ops = wct.getHierarchyOps();
+        for (int i = ops.size() - 1; i >= 0; i--) {
+            final int type = ops.get(i).getType();
+            if (type == HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT) {
+                // Treat as TRANSIT_CHANGE when there is activity reparent.
+                return TRANSIT_CHANGE;
+            }
+            if (type == HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT) {
+                containsCreatingTaskFragment = true;
+            } else if (type == HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT) {
+                containsDeleteTaskFragment = true;
+            }
+        }
+        if (containsCreatingTaskFragment) {
+            return TRANSIT_OPEN;
+        }
+        if (containsDeleteTaskFragment) {
+            return TRANSIT_CLOSE;
+        }
 
-    /**
-     * 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) {}
+        // Use TRANSIT_CHANGE as default.
+        return TRANSIT_CHANGE;
+    }
 
     /**
      * 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);
-    }
-
-    @Override
-    public void applyTransaction(@NonNull WindowContainerTransaction t) {
-        t.setTaskFragmentOrganizer(mInterface);
-        super.applyTransaction(t);
-    }
-
-    // Suppress the lint because it is not a registration method.
-    @SuppressWarnings("ExecutorRegistration")
-    @Override
-    public int applySyncTransaction(@NonNull WindowContainerTransaction t,
-            @NonNull WindowContainerTransactionCallback callback) {
-        t.setTaskFragmentOrganizer(mInterface);
-        return super.applySyncTransaction(t, callback);
+        // 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 dc1f612..8ca763e 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -397,6 +397,8 @@
         private @Surface.Rotation int mEndFixedRotation = ROTATION_UNDEFINED;
         private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
         private @ColorInt int mBackgroundColor;
+        private SurfaceControl mSnapshot = null;
+        private float mSnapshotLuma;
 
         public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
             mContainer = container;
@@ -420,6 +422,8 @@
             mEndFixedRotation = in.readInt();
             mRotationAnimation = in.readInt();
             mBackgroundColor = in.readInt();
+            mSnapshot = in.readTypedObject(SurfaceControl.CREATOR);
+            mSnapshotLuma = in.readFloat();
         }
 
         /** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -489,6 +493,12 @@
             mBackgroundColor = backgroundColor;
         }
 
+        /** Sets a snapshot surface for the "start" state of the container. */
+        public void setSnapshot(@Nullable SurfaceControl snapshot, float luma) {
+            mSnapshot = snapshot;
+            mSnapshotLuma = luma;
+        }
+
         /** @return the container that is changing. May be null if non-remotable (eg. activity) */
         @Nullable
         public WindowContainerToken getContainer() {
@@ -587,6 +597,17 @@
             return mBackgroundColor;
         }
 
+        /** @return a snapshot surface (if applicable). */
+        @Nullable
+        public SurfaceControl getSnapshot() {
+            return mSnapshot;
+        }
+
+        /** @return the luma calculated for the snapshot surface (if applicable). */
+        public float getSnapshotLuma() {
+            return mSnapshotLuma;
+        }
+
         /** @hide */
         @Override
         public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -605,6 +626,8 @@
             dest.writeInt(mEndFixedRotation);
             dest.writeInt(mRotationAnimation);
             dest.writeInt(mBackgroundColor);
+            dest.writeTypedObject(mSnapshot, flags);
+            dest.writeFloat(mSnapshotLuma);
         }
 
         @NonNull
@@ -629,11 +652,13 @@
 
         @Override
         public String toString() {
-            return "{" + mContainer + "(" + mParent + ") leash=" + mLeash
+            String out = "{" + mContainer + "(" + mParent + ") leash=" + mLeash
                     + " m=" + modeToString(mMode) + " f=" + flagsToString(mFlags) + " sb="
                     + mStartAbsBounds + " eb=" + mEndAbsBounds + " eo=" + mEndRelOffset + " r="
                     + mStartRotation + "->" + mEndRotation + ":" + mRotationAnimation
-                    + " endFixedRotation=" + mEndFixedRotation + "}";
+                    + " endFixedRotation=" + mEndFixedRotation;
+            if (mSnapshot != null) out += " snapshot=" + mSnapshot;
+            return out + "}";
         }
     }
 
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index ff7ea31..a99c6be 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -443,6 +443,17 @@
     }
 
     /**
+     * Finds and removes a task and its children using its container token. The task is removed
+     * from recents.
+     * @param containerToken ContainerToken of Task to be removed
+     */
+    @NonNull
+    public WindowContainerTransaction removeTask(@NonNull WindowContainerToken containerToken) {
+        mHierarchyOps.add(HierarchyOp.createForRemoveTask(containerToken.asBinder()));
+        return this;
+    }
+
+    /**
      * Sends a pending intent in sync.
      * @param sender The PendingIntent sender.
      * @param intent The fillIn intent to patch over the sender's base intent.
@@ -669,7 +680,6 @@
      * TaskFragment.
      * @param fragmentToken client assigned unique token to create TaskFragment with specified in
      *                      {@link TaskFragmentCreationParams#getFragmentToken()}.
-     * @hide
      */
     @NonNull
     public WindowContainerTransaction requestFocusOnTaskFragment(@NonNull IBinder fragmentToken) {
@@ -741,10 +751,8 @@
      * @hide
      */
     @NonNull
-    WindowContainerTransaction setTaskFragmentOrganizer(@NonNull ITaskFragmentOrganizer organizer) {
-        if (mTaskFragmentOrganizer != null) {
-            throw new IllegalStateException("Can't set multiple organizers for one transaction.");
-        }
+    public WindowContainerTransaction setTaskFragmentOrganizer(
+            @NonNull ITaskFragmentOrganizer organizer) {
         mTaskFragmentOrganizer = organizer;
         return this;
     }
@@ -1142,6 +1150,7 @@
         public static final int HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER = 17;
         public static final int HIERARCHY_OP_TYPE_REQUEST_FOCUS_ON_TASK_FRAGMENT = 18;
         public static final int HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP = 19;
+        public static final int HIERARCHY_OP_TYPE_REMOVE_TASK = 20;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1271,6 +1280,13 @@
                     .build();
         }
 
+        /** create a hierarchy op for deleting a task **/
+        public static HierarchyOp createForRemoveTask(@NonNull IBinder container) {
+            return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_TASK)
+                    .setContainer(container)
+                    .build();
+        }
+
         /** Only creates through {@link Builder}. */
         private HierarchyOp(int type) {
             mType = type;
@@ -1454,6 +1470,8 @@
                 case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
                     return "{setAlwaysOnTop: container=" + mContainer
                             + " alwaysOnTop=" + mAlwaysOnTop + "}";
+                case HIERARCHY_OP_TYPE_REMOVE_TASK:
+                    return "{RemoveTask: task=" + mContainer + "}";
                 default:
                     return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
                             + " mToTop=" + mToTop
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 f6c64732..5cf7e36 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -63,6 +63,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Insets;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.drawable.AnimatedVectorDrawable;
@@ -141,11 +142,13 @@
 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;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.function.Supplier;
 
 /**
@@ -281,6 +284,7 @@
     private long mQueriedSharingShortcutsTimeMs;
 
     private int mCurrAvailableWidth = 0;
+    private Insets mLastAppliedInsets = null;
     private int mLastNumberOfChildren = -1;
     private int mMaxTargetsPerRow = 1;
 
@@ -1632,6 +1636,8 @@
         if (mChooserMultiProfilePagerAdapter.getInactiveListAdapter() != null) {
             mChooserMultiProfilePagerAdapter.getInactiveListAdapter().destroyAppPredictor();
         }
+        mPersonalAppPredictor = null;
+        mWorkAppPredictor = null;
     }
 
     @Override // ResolverListCommunicator
@@ -2544,7 +2550,11 @@
                 || gridAdapter.calculateChooserTargetWidth(availableWidth)
                 || recyclerView.getAdapter() == null
                 || availableWidth != mCurrAvailableWidth;
+
+        boolean insetsChanged = !Objects.equals(mLastAppliedInsets, mSystemWindowInsets);
+
         if (isLayoutUpdated
+                || insetsChanged
                 || mLastNumberOfChildren != recyclerView.getChildCount()) {
             mCurrAvailableWidth = availableWidth;
             if (isLayoutUpdated) {
@@ -2565,7 +2575,7 @@
                 return;
             }
 
-            if (mLastNumberOfChildren == recyclerView.getChildCount()) {
+            if (mLastNumberOfChildren == recyclerView.getChildCount() && !insetsChanged) {
                 return;
             }
 
@@ -2576,6 +2586,7 @@
                 int offset = calculateDrawerOffset(top, bottom, recyclerView, gridAdapter);
                 mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
                 mEnterTransitionAnimationDelegate.markOffsetCalculated();
+                mLastAppliedInsets = mSystemWindowInsets;
             });
         }
     }
@@ -2942,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();
@@ -3068,7 +3081,12 @@
             mChooserMultiProfilePagerAdapter.setupContainerPadding(
                     getActiveEmptyStateView().findViewById(R.id.resolver_empty_state_container));
         }
-        return super.onApplyWindowInsets(v, insets);
+
+        WindowInsets result = super.onApplyWindowInsets(v, insets);
+        if (mResolverDrawerLayout != null) {
+            mResolverDrawerLayout.requestLayout();
+        }
+        return result;
     }
 
     private void setHorizontalScrollingEnabled(boolean enabled) {
@@ -3706,6 +3724,7 @@
             this.mRows = rows;
             this.mCellCountPerRow = cellCountPerRow;
             this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
+            Arrays.fill(mCellVisibility, true);
             this.mListAdapterSupplier = listAdapterSupplier;
         }
 
@@ -4069,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;
@@ -4097,7 +4118,9 @@
 
         @Override
         public void cancel() {
-            mRootView.setAlpha(mFromAlpha);
+            if (mRootView != null) {
+                mRootView.setAlpha(mFromAlpha);
+            }
             cleanup();
             super.cancel();
         }
@@ -4108,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/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index be7501f..1e52087 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -22,6 +22,9 @@
 import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_END;
 import static android.view.inputmethod.InputConnectionProto.SELECTED_TEXT_START;
 
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.text.Editable;
 import android.text.Selection;
@@ -31,12 +34,19 @@
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.DeleteGesture;
 import android.view.inputmethod.DumpableInputConnection;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.HandwritingGesture;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.SelectGesture;
 import android.widget.TextView;
 
+import java.util.concurrent.Executor;
+import java.util.function.IntConsumer;
+
 /**
  * Base class for an editable InputConnection instance. This is created by {@link TextView} or
  * {@link android.widget.EditText}.
@@ -257,6 +267,25 @@
     }
 
     @Override
+    public void performHandwritingGesture(
+            @NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor,
+            @Nullable IntConsumer consumer) {
+        int result;
+        if (gesture instanceof SelectGesture) {
+            result = mTextView.performHandwritingSelectGesture((SelectGesture) gesture);
+        } else if (gesture instanceof DeleteGesture) {
+            result = mTextView.performHandwritingDeleteGesture((DeleteGesture) gesture);
+        } else if (gesture instanceof InsertGesture) {
+            result = mTextView.performHandwritingInsertGesture((InsertGesture) gesture);
+        } else {
+            result = HANDWRITING_GESTURE_RESULT_UNSUPPORTED;
+        }
+        if (executor != null && consumer != null) {
+            executor.execute(() -> consumer.accept(result));
+        }
+    }
+
+    @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         CharSequence editableText = mTextView.getText();
diff --git a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
index 7a219c6..f456e85 100644
--- a/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
+++ b/core/java/com/android/internal/inputmethod/IRemoteInputConnection.aidl
@@ -25,6 +25,8 @@
 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.TextAttribute;
 
@@ -99,6 +101,12 @@
     void performHandwritingDeleteGesture(in InputConnectionCommandHeader header,
             in DeleteGesture 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 33cb56f..bbf0a76 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;
@@ -227,6 +227,8 @@
                 return "HIDE_DOCKED_STACK_ATTACHED";
             case SoftInputShowHideReason.HIDE_RECENTS_ANIMATION:
                 return "HIDE_RECENTS_ANIMATION";
+            case SoftInputShowHideReason.HIDE_BUBBLES:
+                return "HIDE_BUBBLES";
             case SoftInputShowHideReason.HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR:
                 return "HIDE_SAME_WINDOW_FOCUSED_WITHOUT_EDITOR";
             case SoftInputShowHideReason.HIDE_REMOVE_CLIENT:
@@ -251,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;
         }
@@ -274,25 +278,32 @@
         if ((gestureTypeFlags & HandwritingGesture.GESTURE_TYPE_DELETE) != 0) {
             joiner.add("DELETE");
         }
+        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..6a7028d 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -48,6 +48,8 @@
 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.TextAttribute;
 import android.view.inputmethod.TextSnapshot;
@@ -997,6 +999,22 @@
         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/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index 6909965..f097bf7 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -16,16 +16,23 @@
 
 package com.android.internal.os;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.BatteryStats.BitDescription;
 import android.os.BatteryStats.HistoryItem;
 import android.os.BatteryStats.HistoryStepDetails;
 import android.os.BatteryStats.HistoryTag;
+import android.os.BatteryStats.MeasuredEnergyDetails;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.ParcelFormatException;
 import android.os.Process;
 import android.os.StatFs;
 import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.os.Trace;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -113,6 +120,9 @@
     // therefore the tag value is written in the parcel
     static final int TAG_FIRST_OCCURRENCE_FLAG = 0x8000;
 
+    static final int EXTENSION_MEASURED_ENERGY_HEADER_FLAG = 0x00000001;
+    static final int EXTENSION_MEASURED_ENERGY_FLAG = 0x00000002;
+
     private final Parcel mHistoryBuffer;
     private final File mSystemDir;
     private final HistoryStepDetailsCalculator mStepDetailsCalculator;
@@ -183,6 +193,7 @@
     private long mTrackRunningHistoryElapsedRealtimeMs = 0;
     private long mTrackRunningHistoryUptimeMs = 0;
     private long mHistoryBaseTimeMs;
+    private boolean mMeasuredEnergyHeaderWritten = false;
 
     private byte mLastHistoryStepLevel = 0;
 
@@ -205,6 +216,42 @@
     }
 
     /**
+     * A delegate for android.os.Trace to allow testing static calls. Due to
+     * limitations in Android Tracing (b/153319140), the delegate also records
+     * counter values in system properties which allows reading the value at the
+     * start of a tracing session. This overhead is limited to userdebug builds.
+     * On user builds, tracing still occurs but the counter value will be missing
+     * until the first change occurs.
+     */
+    @VisibleForTesting
+    public static class TraceDelegate {
+        // Note: certain tests currently run as platform_app which is not allowed
+        // to set debug system properties. To ensure that system properties are set
+        // only when allowed, we check the current UID.
+        private final boolean mShouldSetProperty =
+                Build.IS_USERDEBUG && (Process.myUid() == Process.SYSTEM_UID);
+
+        /**
+         * Returns true if trace counters should be recorded.
+         */
+        public boolean tracingEnabled() {
+            return Trace.isTagEnabled(Trace.TRACE_TAG_POWER) || mShouldSetProperty;
+        }
+
+        /**
+         * Records the counter value with the given name.
+         */
+        public void traceCounter(@NonNull String name, int value) {
+            Trace.traceCounter(Trace.TRACE_TAG_POWER, name, value);
+            if (mShouldSetProperty) {
+                SystemProperties.set("debug.tracing." + name, Integer.toString(value));
+            }
+        }
+    }
+
+    private TraceDelegate mTracer;
+
+    /**
      * Constructor
      *
      * @param systemDir            typically /data/system
@@ -214,19 +261,20 @@
     public BatteryStatsHistory(File systemDir, int maxHistoryFiles, int maxHistoryBufferSize,
             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
         this(Parcel.obtain(), systemDir, maxHistoryFiles, maxHistoryBufferSize,
-                stepDetailsCalculator, clock);
+                stepDetailsCalculator, clock, new TraceDelegate());
         initHistoryBuffer();
     }
 
     @VisibleForTesting
     public BatteryStatsHistory(Parcel historyBuffer, File systemDir,
             int maxHistoryFiles, int maxHistoryBufferSize,
-            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
+            HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock, TraceDelegate tracer) {
         mHistoryBuffer = historyBuffer;
         mSystemDir = systemDir;
         mMaxHistoryFiles = maxHistoryFiles;
         mMaxHistoryBufferSize = maxHistoryBufferSize;
         mStepDetailsCalculator = stepDetailsCalculator;
+        mTracer = tracer;
         mClock = clock;
 
         mHistoryDir = new File(systemDir, HISTORY_DIR);
@@ -267,6 +315,7 @@
 
     public BatteryStatsHistory(HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
         mStepDetailsCalculator = stepDetailsCalculator;
+        mTracer = new TraceDelegate();
         mClock = clock;
 
         mHistoryBuffer = Parcel.obtain();
@@ -282,6 +331,7 @@
     private BatteryStatsHistory(Parcel historyBuffer,
             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock) {
         mHistoryBuffer = historyBuffer;
+        mTracer = new TraceDelegate();
         mClock = clock;
         mSystemDir = null;
         mHistoryDir = null;
@@ -293,6 +343,7 @@
         mLastHistoryElapsedRealtimeMs = 0;
         mTrackRunningHistoryElapsedRealtimeMs = 0;
         mTrackRunningHistoryUptimeMs = 0;
+        mMeasuredEnergyHeaderWritten = false;
 
         mHistoryBuffer.setDataSize(0);
         mHistoryBuffer.setDataPosition(0);
@@ -332,7 +383,7 @@
         // Make a copy of battery history to avoid concurrent modification.
         Parcel historyBuffer = Parcel.obtain();
         historyBuffer.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
-        return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null);
+        return new BatteryStatsHistory(historyBuffer, mSystemDir, 0, 0, null, null, mTracer);
     }
 
     /**
@@ -933,6 +984,16 @@
     }
 
     /**
+     * Records measured energy data.
+     */
+    public void recordMeasuredEnergyDetails(long elapsedRealtimeMs, long uptimeMs,
+            MeasuredEnergyDetails measuredEnergyDetails) {
+        mHistoryCur.measuredEnergyDetails = measuredEnergyDetails;
+        mHistoryCur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+        writeHistoryItem(elapsedRealtimeMs, uptimeMs);
+    }
+
+    /**
      * Records a history item with the amount of charge consumed by WiFi.  Used on certain devices
      * equipped with on-device power metering.
      */
@@ -1104,6 +1165,30 @@
     }
 
     /**
+     * Writes changes to a HistoryItem state bitmap to Atrace.
+     */
+    private void recordTraceCounters(int oldval, int newval, BitDescription[] descriptions) {
+        if (!mTracer.tracingEnabled()) return;
+
+        int diff = oldval ^ newval;
+        if (diff == 0) return;
+
+        for (int i = 0; i < descriptions.length; i++) {
+            BitDescription bd = descriptions[i];
+            if ((diff & bd.mask) == 0) continue;
+
+            int value;
+            if (bd.shift < 0) {
+                value = (newval & bd.mask) != 0 ? 1 : 0;
+            } else {
+                value = (newval & bd.mask) >> bd.shift;
+            }
+
+            mTracer.traceCounter("battery_stats." + bd.name, value);
+        }
+    }
+
+    /**
      * Writes the current history item to history.
      */
     public void writeHistoryItem(long elapsedRealtimeMs, long uptimeMs) {
@@ -1143,6 +1228,12 @@
                     + Integer.toHexString(diffStates2) + " lastDiff2="
                     + Integer.toHexString(lastDiffStates2));
         }
+
+        recordTraceCounters(mHistoryLastWritten.states,
+                cur.states & mActiveHistoryStates, BatteryStats.HISTORY_STATE_DESCRIPTIONS);
+        recordTraceCounters(mHistoryLastWritten.states2,
+                cur.states2 & mActiveHistoryStates2, BatteryStats.HISTORY_STATE2_DESCRIPTIONS);
+
         if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
                 && timeDiffMs < 1000 && (diffStates & lastDiffStates) == 0
                 && (diffStates2 & lastDiffStates2) == 0
@@ -1219,6 +1310,8 @@
             for (Map.Entry<HistoryTag, Integer> entry : mHistoryTagPool.entrySet()) {
                 entry.setValue(entry.getValue() | BatteryStatsHistory.TAG_FIRST_OCCURRENCE_FLAG);
             }
+            mMeasuredEnergyHeaderWritten = false;
+
             // Make a copy of mHistoryCur.
             HistoryItem copy = new HistoryItem();
             copy.setTo(cur);
@@ -1256,6 +1349,7 @@
         cur.eventCode = HistoryItem.EVENT_NONE;
         cur.eventTag = null;
         cur.tagsFirstOccurrence = false;
+        cur.measuredEnergyDetails = null;
         if (DEBUG) {
             Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
                     + " now " + mHistoryBuffer.dataPosition()
@@ -1348,6 +1442,7 @@
             return;
         }
 
+        int extensionFlags = 0;
         final long deltaTime = cur.time - last.time;
         final int lastBatteryLevelInt = buildBatteryLevelInt(last);
         final int lastStateInt = buildStateInt(last);
@@ -1374,6 +1469,17 @@
         if (stateIntChanged) {
             firstToken |= BatteryStatsHistory.DELTA_STATE_FLAG;
         }
+        if (cur.measuredEnergyDetails != null) {
+            extensionFlags |= BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_FLAG;
+            if (!mMeasuredEnergyHeaderWritten) {
+                extensionFlags |= BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_HEADER_FLAG;
+            }
+        }
+        if (extensionFlags != 0) {
+            cur.states2 |= HistoryItem.STATE2_EXTENSIONS_FLAG;
+        } else {
+            cur.states2 &= ~HistoryItem.STATE2_EXTENSIONS_FLAG;
+        }
         final boolean state2IntChanged = cur.states2 != last.states2;
         if (state2IntChanged) {
             firstToken |= BatteryStatsHistory.DELTA_STATE2_FLAG;
@@ -1491,6 +1597,28 @@
         }
         dest.writeDouble(cur.modemRailChargeMah);
         dest.writeDouble(cur.wifiRailChargeMah);
+        if (extensionFlags != 0) {
+            dest.writeInt(extensionFlags);
+            if (cur.measuredEnergyDetails != null) {
+                if (DEBUG) {
+                    Slog.i(TAG, "WRITE DELTA: measuredEnergyDetails=" + cur.measuredEnergyDetails);
+                }
+                if (!mMeasuredEnergyHeaderWritten) {
+                    MeasuredEnergyDetails.EnergyConsumer[] consumers =
+                            cur.measuredEnergyDetails.consumers;
+                    dest.writeInt(consumers.length);
+                    for (MeasuredEnergyDetails.EnergyConsumer consumer : consumers) {
+                        dest.writeInt(consumer.type);
+                        dest.writeInt(consumer.ordinal);
+                        dest.writeString(consumer.name);
+                    }
+                    mMeasuredEnergyHeaderWritten = true;
+                }
+                for (long chargeUC : cur.measuredEnergyDetails.chargeUC) {
+                    dest.writeLong(chargeUC);
+                }
+            }
+        }
     }
 
     private int buildBatteryLevelInt(HistoryItem h) {
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index 1bf878cb..ee3d15b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -33,6 +33,7 @@
     private final BatteryStats.HistoryStepDetails mReadHistoryStepDetails =
             new BatteryStats.HistoryStepDetails();
     private final SparseArray<BatteryStats.HistoryTag> mHistoryTags = new SparseArray<>();
+    private BatteryStats.MeasuredEnergyDetails mMeasuredEnergyDetails;
 
     public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) {
         mBatteryStatsHistory = history;
@@ -198,6 +199,40 @@
         }
         cur.modemRailChargeMah = src.readDouble();
         cur.wifiRailChargeMah = src.readDouble();
+        if ((cur.states2 & BatteryStats.HistoryItem.STATE2_EXTENSIONS_FLAG) != 0) {
+            final int extensionFlags = src.readInt();
+            if ((extensionFlags & BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_HEADER_FLAG) != 0) {
+                if (mMeasuredEnergyDetails == null) {
+                    mMeasuredEnergyDetails = new BatteryStats.MeasuredEnergyDetails();
+                }
+
+                final int consumerCount = src.readInt();
+                mMeasuredEnergyDetails.consumers =
+                        new BatteryStats.MeasuredEnergyDetails.EnergyConsumer[consumerCount];
+                mMeasuredEnergyDetails.chargeUC = new long[consumerCount];
+                for (int i = 0; i < consumerCount; i++) {
+                    BatteryStats.MeasuredEnergyDetails.EnergyConsumer consumer =
+                            new BatteryStats.MeasuredEnergyDetails.EnergyConsumer();
+                    consumer.type = src.readInt();
+                    consumer.ordinal = src.readInt();
+                    consumer.name = src.readString();
+                    mMeasuredEnergyDetails.consumers[i] = consumer;
+                }
+            }
+
+            if ((extensionFlags & BatteryStatsHistory.EXTENSION_MEASURED_ENERGY_FLAG) != 0) {
+                if (mMeasuredEnergyDetails == null) {
+                    throw new IllegalStateException("MeasuredEnergyDetails without a header");
+                }
+
+                for (int i = 0; i < mMeasuredEnergyDetails.chargeUC.length; i++) {
+                    mMeasuredEnergyDetails.chargeUC[i] = src.readLong();
+                }
+                cur.measuredEnergyDetails = mMeasuredEnergyDetails;
+            }
+        } else {
+            cur.measuredEnergyDetails = null;
+        }
     }
 
     private boolean readHistoryTag(Parcel src, int index, BatteryStats.HistoryTag outTag) {
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/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index b1e7d15..ea5f0b2 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -1001,16 +1001,24 @@
     }
 
     /**
+     * This will enable jdwp by default for all apps. It is OK to cache this property
+     * because we expect to reboot the system whenever this property changes
+     */
+    private static final boolean ENABLE_JDWP = SystemProperties.get(
+                          "persist.debuggable.dalvik.vm.jdwp.enabled").equals("1");
+
+    /**
      * Applies debugger system properties to the zygote arguments.
      *
-     * If "ro.debuggable" is "1", all apps are debuggable. Otherwise,
-     * the debugger state is specified via the "--enable-jdwp" flag
-     * in the spawn request.
+     * For eng builds all apps are debuggable. On userdebug and user builds
+     * if persist.debuggable.dalvik.vm.jdwp.enabled is 1 all apps are
+     * debuggable. Otherwise, the debugger state is specified via the
+     * "--enable-jdwp" flag in the spawn request.
      *
      * @param args non-null; zygote spawner args
      */
     static void applyDebuggerSystemProperty(ZygoteArguments args) {
-        if (RoSystemProperties.DEBUGGABLE) {
+        if (Build.IS_ENG || ENABLE_JDWP) {
             args.mRuntimeFlags |= Zygote.DEBUG_ENABLE_JDWP;
         }
     }
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/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 65bec0e..44cfe1a 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -264,11 +264,6 @@
     void stopTracing();
 
     /**
-     * Handles a logging command from the WM shell command.
-     */
-    void handleWindowManagerLoggingCommand(in String[] args, in ParcelFileDescriptor outFd);
-
-    /**
      * If true, suppresses the ambient display from showing. If false, re-enables the ambient
      * display.
      */
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/LocalImageResolver.java b/core/java/com/android/internal/widget/LocalImageResolver.java
index b11ea29..9ef7ce38 100644
--- a/core/java/com/android/internal/widget/LocalImageResolver.java
+++ b/core/java/com/android/internal/widget/LocalImageResolver.java
@@ -19,6 +19,8 @@
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.ImageDecoder;
@@ -109,13 +111,13 @@
                 }
                 break;
             case Icon.TYPE_RESOURCE:
-                if (!(TextUtils.isEmpty(icon.getResPackage())
-                        || context.getPackageName().equals(icon.getResPackage()))) {
-                    // We can't properly resolve icons from other packages here, so fall back.
+                Resources res = resolveResourcesForIcon(context, icon);
+                if (res == null) {
+                    // We couldn't resolve resources properly, fall back to icon loading.
                     return icon.loadDrawable(context);
                 }
 
-                Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight);
+                Drawable result = resolveImage(res, icon.getResId(), maxWidth, maxHeight);
                 if (result != null) {
                     return tintDrawable(icon, result);
                 }
@@ -159,6 +161,13 @@
     }
 
     @Nullable
+    private static Drawable resolveImage(Resources res, @DrawableRes int resId, int maxWidth,
+            int maxHeight) {
+        final ImageDecoder.Source source = ImageDecoder.createSource(res, resId);
+        return resolveImage(source, maxWidth, maxHeight);
+    }
+
+    @Nullable
     private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
             int maxHeight) {
 
@@ -259,4 +268,52 @@
         }
         return icon.getUri();
     }
+
+    /**
+     * Resolves the correct resources package for a given Icon - it may come from another
+     * package.
+     *
+     * @see Icon#loadDrawableInner(Context)
+     * @hide
+     *
+     * @return resources instance if the operation succeeded, null otherwise
+     */
+    @Nullable
+    @VisibleForTesting
+    public static Resources resolveResourcesForIcon(Context context, Icon icon) {
+        if (icon.getType() != Icon.TYPE_RESOURCE) {
+            return null;
+        }
+
+        // Icons cache resolved resources, use cache if available.
+        Resources res = icon.getResources();
+        if (res != null) {
+            return res;
+        }
+
+        String resPackage = icon.getResPackage();
+        // No package means we try to use current context.
+        if (TextUtils.isEmpty(resPackage) || context.getPackageName().equals(resPackage)) {
+            return context.getResources();
+        }
+
+        if ("android".equals(resPackage)) {
+            return Resources.getSystem();
+        }
+
+        final PackageManager pm = context.getPackageManager();
+        try {
+            ApplicationInfo ai = pm.getApplicationInfo(resPackage,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.GET_SHARED_LIBRARY_FILES);
+            if (ai != null) {
+                return pm.getResourcesForApplication(ai);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, String.format("Unable to resolve package %s for icon %s", resPackage, icon));
+            return null;
+        }
+
+        return null;
+    }
 }
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 9f3f335..03e7fd1 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -26,7 +26,6 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.storage.StorageManager;
 import android.text.TextUtils;
 
 import com.android.internal.util.ArrayUtils;
@@ -347,7 +346,7 @@
     @Override
     public int hashCode() {
         // Effective Java — Always override hashCode when you override equals
-        return (17 + mType) * 31 + mCredential.hashCode();
+        return Objects.hash(mType, Arrays.hashCode(mCredential));
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/PointerLocationView.java b/core/java/com/android/internal/widget/PointerLocationView.java
index 9ee9b82..80d50ff 100644
--- a/core/java/com/android/internal/widget/PointerLocationView.java
+++ b/core/java/com/android/internal/widget/PointerLocationView.java
@@ -90,8 +90,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() {
@@ -679,11 +681,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);
 
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index 7f50204..14699e7 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -95,3 +95,7 @@
 # Battery
 per-file com_android_internal_os_Kernel* = file:/BATTERY_STATS_OWNERS
 per-file com_android_internal_os_*MultiStateCounter* = file:/BATTERY_STATS_OWNERS
+
+# PM
+per-file com_android_internal_content_* = file:/PACKAGE_MANAGER_OWNERS
+
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/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index be82879..acf4da6 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -17,28 +17,25 @@
 #define LOG_TAG "NativeLibraryHelper"
 //#define LOG_NDEBUG 0
 
-#include "core_jni_helpers.h"
-
-#include <nativehelper/ScopedUtfChars.h>
 #include <androidfw/ZipFileRO.h>
 #include <androidfw/ZipUtils.h>
-#include <utils/Log.h>
-#include <utils/Vector.h>
-
-#include <zlib.h>
-
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <inttypes.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <zlib.h>
 
 #include <memory>
 
+#include "core_jni_helpers.h"
+
 #define APK_LIB "lib/"
 #define APK_LIB_LEN (sizeof(APK_LIB) - 1)
 
@@ -156,7 +153,7 @@
     size_t* total = (size_t*) arg;
     uint32_t uncompLen;
 
-    if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, NULL, NULL)) {
+    if (!zipFile->getEntryInfo(zipEntry, nullptr, &uncompLen, nullptr, nullptr, nullptr, nullptr)) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
@@ -186,7 +183,7 @@
     uint16_t method;
     off64_t offset;
 
-    if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) {
+    if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, nullptr, &offset, &when, &crc)) {
         ALOGE("Couldn't read zip entry info\n");
         return INSTALL_FAILED_INVALID_APK;
     }
@@ -307,24 +304,24 @@
 class NativeLibrariesIterator {
 private:
     NativeLibrariesIterator(ZipFileRO* zipFile, bool debuggable, void* cookie)
-        : mZipFile(zipFile), mDebuggable(debuggable), mCookie(cookie), mLastSlash(NULL) {
+          : mZipFile(zipFile), mDebuggable(debuggable), mCookie(cookie), mLastSlash(nullptr) {
         fileName[0] = '\0';
     }
 
 public:
     static NativeLibrariesIterator* create(ZipFileRO* zipFile, bool debuggable) {
-        void* cookie = NULL;
+        void* cookie = nullptr;
         // Do not specify a suffix to find both .so files and gdbserver.
-        if (!zipFile->startIteration(&cookie, APK_LIB, NULL /* suffix */)) {
-            return NULL;
+        if (!zipFile->startIteration(&cookie, APK_LIB, nullptr /* suffix */)) {
+            return nullptr;
         }
 
         return new NativeLibrariesIterator(zipFile, debuggable, cookie);
     }
 
     ZipEntryRO next() {
-        ZipEntryRO next = NULL;
-        while ((next = mZipFile->nextEntry(mCookie)) != NULL) {
+        ZipEntryRO next = nullptr;
+        while ((next = mZipFile->nextEntry(mCookie)) != nullptr) {
             // Make sure this entry has a filename.
             if (mZipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
                 continue;
@@ -338,7 +335,7 @@
             }
 
             const char* lastSlash = strrchr(fileName, '/');
-            ALOG_ASSERT(lastSlash != NULL, "last slash was null somehow for %s\n", fileName);
+            ALOG_ASSERT(lastSlash != nullptr, "last slash was null somehow for %s\n", fileName);
 
             // Skip directories.
             if (*(lastSlash + 1) == 0) {
@@ -389,24 +386,23 @@
 iterateOverNativeFiles(JNIEnv *env, jlong apkHandle, jstring javaCpuAbi,
                        jboolean debuggable, iterFunc callFunc, void* callArg) {
     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
-    if (zipFile == NULL) {
+    if (zipFile == nullptr) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
     std::unique_ptr<NativeLibrariesIterator> it(
             NativeLibrariesIterator::create(zipFile, debuggable));
-    if (it.get() == NULL) {
+    if (it.get() == nullptr) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
     const ScopedUtfChars cpuAbi(env, javaCpuAbi);
-    if (cpuAbi.c_str() == NULL) {
-        // This would've thrown, so this return code isn't observable by
-        // Java.
+    if (cpuAbi.c_str() == nullptr) {
+        // This would've thrown, so this return code isn't observable by Java.
         return INSTALL_FAILED_INVALID_APK;
     }
-    ZipEntryRO entry = NULL;
-    while ((entry = it->next()) != NULL) {
+    ZipEntryRO entry = nullptr;
+    while ((entry = it->next()) != nullptr) {
         const char* fileName = it->currentEntry();
         const char* lastSlash = it->lastSlash();
 
@@ -427,31 +423,30 @@
     return INSTALL_SUCCEEDED;
 }
 
-
-static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supportedAbisArray,
-        jboolean debuggable) {
-    const int numAbis = env->GetArrayLength(supportedAbisArray);
-    Vector<ScopedUtfChars*> supportedAbis;
-
-    for (int i = 0; i < numAbis; ++i) {
-        supportedAbis.add(new ScopedUtfChars(env,
-            (jstring) env->GetObjectArrayElement(supportedAbisArray, i)));
-    }
-
+static int findSupportedAbi(JNIEnv* env, jlong apkHandle, jobjectArray supportedAbisArray,
+                            jboolean debuggable) {
     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
-    if (zipFile == NULL) {
+    if (zipFile == nullptr) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
     std::unique_ptr<NativeLibrariesIterator> it(
             NativeLibrariesIterator::create(zipFile, debuggable));
-    if (it.get() == NULL) {
+    if (it.get() == nullptr) {
         return INSTALL_FAILED_INVALID_APK;
     }
 
-    ZipEntryRO entry = NULL;
+    const int numAbis = env->GetArrayLength(supportedAbisArray);
+
+    std::vector<ScopedUtfChars> supportedAbis;
+    supportedAbis.reserve(numAbis);
+    for (int i = 0; i < numAbis; ++i) {
+        supportedAbis.emplace_back(env, (jstring)env->GetObjectArrayElement(supportedAbisArray, i));
+    }
+
+    ZipEntryRO entry = nullptr;
     int status = NO_NATIVE_LIBRARIES;
-    while ((entry = it->next()) != NULL) {
+    while ((entry = it->next()) != nullptr) {
         // We're currently in the lib/ directory of the APK, so it does have some native
         // code. We should return INSTALL_FAILED_NO_MATCHING_ABIS if none of the
         // libraries match.
@@ -466,8 +461,8 @@
         const char* abiOffset = fileName + APK_LIB_LEN;
         const size_t abiSize = lastSlash - abiOffset;
         for (int i = 0; i < numAbis; i++) {
-            const ScopedUtfChars* abi = supportedAbis[i];
-            if (abi->size() == abiSize && !strncmp(abiOffset, abi->c_str(), abiSize)) {
+            const ScopedUtfChars& abi = supportedAbis[i];
+            if (abi.size() == abiSize && !strncmp(abiOffset, abi.c_str(), abiSize)) {
                 // The entry that comes in first (i.e. with a lower index) has the higher priority.
                 if (((i < status) && (status >= 0)) || (status < 0) ) {
                     status = i;
@@ -476,10 +471,6 @@
         }
     }
 
-    for (int i = 0; i < numAbis; ++i) {
-        delete supportedAbis[i];
-    }
-
     return status;
 }
 
@@ -521,19 +512,19 @@
 com_android_internal_content_NativeLibraryHelper_hasRenderscriptBitcode(JNIEnv *env, jclass clazz,
         jlong apkHandle) {
     ZipFileRO* zipFile = reinterpret_cast<ZipFileRO*>(apkHandle);
-    void* cookie = NULL;
-    if (!zipFile->startIteration(&cookie, NULL /* prefix */, RS_BITCODE_SUFFIX)) {
+    void* cookie = nullptr;
+    if (!zipFile->startIteration(&cookie, nullptr /* prefix */, RS_BITCODE_SUFFIX)) {
         return APK_SCAN_ERROR;
     }
 
     char fileName[PATH_MAX];
-    ZipEntryRO next = NULL;
-    while ((next = zipFile->nextEntry(cookie)) != NULL) {
+    ZipEntryRO next = nullptr;
+    while ((next = zipFile->nextEntry(cookie)) != nullptr) {
         if (zipFile->getEntryFileName(next, fileName, sizeof(fileName))) {
             continue;
         }
         const char* lastSlash = strrchr(fileName, '/');
-        const char* baseName = (lastSlash == NULL) ? fileName : fileName + 1;
+        const char* baseName = (lastSlash == nullptr) ? fileName : fileName + 1;
         if (isFilenameSafe(baseName)) {
             zipFile->endIteration(cookie);
             return BITCODE_PRESENT;
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/com_android_internal_security_VerityUtils.cpp b/core/jni/com_android_internal_security_VerityUtils.cpp
index c5b3d8a..8305bd0 100644
--- a/core/jni/com_android_internal_security_VerityUtils.cpp
+++ b/core/jni/com_android_internal_security_VerityUtils.cpp
@@ -111,10 +111,10 @@
     ScopedUtfChars path(env, filePath);
     ::android::base::unique_fd rfd(open(path.c_str(), O_RDONLY | O_CLOEXEC));
     if (rfd.get() < 0) {
-        return rfd.get();
+        return -errno;
     }
-    if (auto err = ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data); err < 0) {
-        return err;
+    if (::ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) {
+        return -errno;
     }
 
     if (data->digest_algorithm != FS_VERITY_HASH_ALG_SHA256) {
diff --git a/core/proto/android/app/notificationmanager.proto b/core/proto/android/app/notificationmanager.proto
index b88315e..3342c79 100644
--- a/core/proto/android/app/notificationmanager.proto
+++ b/core/proto/android/app/notificationmanager.proto
@@ -45,6 +45,8 @@
         MEDIA = 7;
         // System (catch-all for non-never suppressible sounds) are prioritized.
         SYSTEM = 8;
+        // Priority conversations are prioritized
+        CONVERSATIONS = 9;
     }
     repeated Category priority_categories = 1;
 
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/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 505ef30..537efc0 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -243,6 +243,7 @@
     optional bool is_root_display_area = 5;
     optional int32 feature_id = 6;
     optional bool is_organized = 7;
+    optional bool is_ignoring_orientation_request = 8;
 }
 
 /* represents a generic child of a DisplayArea */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5b4fc56..4d41c30 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -923,7 +923,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.SEND_SMS"
@@ -937,7 +937,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_SMS"
@@ -951,7 +951,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_SMS"
@@ -965,7 +965,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
@@ -979,7 +979,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_MMS"
@@ -1014,7 +1014,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
 
          @hide Pending API council approval -->
@@ -1059,7 +1059,7 @@
       targetSdkVersion}</a> is 4 or higher.
 
       <p> This is a soft restricted permission which cannot be held by an app it its
-      full form until the installer on record whitelists the permission.
+      full form until the installer on record allowlists the permission.
       Specifically, if the permission is allowlisted the holder app can access
       external storage and the visual and aural media collections while if the
       permission is not allowlisted the holder app can only access to the visual
@@ -1239,7 +1239,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
@@ -1301,7 +1301,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_CALL_LOG"
@@ -1325,7 +1325,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
@@ -1341,7 +1341,7 @@
          <p>Protection level: dangerous
 
          <p> This is a hard restricted permission which cannot be held by an app until
-         the installer on record whitelists the permission. For more details see
+         the installer on record allowlists the permission. For more details see
          {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
 
          @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
@@ -4771,7 +4771,7 @@
                 android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to allowlist restricted permissions
-         on any of the whitelists.
+         on any of the allowlists.
     @hide -->
     <permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS"
                 android:protectionLevel="signature|installer" />
diff --git a/core/res/OWNERS b/core/res/OWNERS
index c54638a..d8fc218 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -37,7 +37,7 @@
 per-file res/values/dimens_car.xml = file:/platform/packages/services/Car:/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 56b8260..9b997bf 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Te veel pogings. Vingerafdruksensor is gedeaktiveer."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nie gemerk nie"</string>
     <string name="selected" msgid="6614607926197755875">"gekies"</string>
     <string name="not_selected" msgid="410652016565864475">"nie gekies nie"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Een ster uit {max}}other{# sterre uit {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"aan die gang"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Voltooi handeling met"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Voltooi handeling met gebruik van %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Streekvoorkeur"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Voer taalnaam in"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Voorgestel"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Voorgestel"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Voorgestelde tale"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Voorgestelde streke"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Alle tale"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Gee <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> toegang tot alle toestelloglêers?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Gee eenmalige toegang"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Moenie toelaat nie"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Toestelloglêers teken aan wat op jou toestel gebeur. Programme kan hierdie loglêers gebruik om kwessies op te spoor en reg te stel.\n\nSommige loglêers bevat dalk sensitiewe inligting en daarom moet jy toegang tot alle toestelloglêers net gee aan programme wat jy vertrou. \n\nAs jy nie vir hierdie program toegang tot alle toestelloglêers gee nie, het die program steeds toegang tot eie loglêers. Jou toestelvervaardiger het dalk steeds toegang tot sommige loglêers of inligting op jou toestel."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Moenie weer wys nie"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Wysig"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a68c514..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"በጣም ብዙ ሙከራዎች። የጣት አሻራ ዳሳሽ ተሰናክሏል።"</string>
+    <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>
@@ -634,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>
@@ -1162,13 +1163,12 @@
     <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>
     <string name="not_selected" msgid="410652016565864475">"አልተመረጠም"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{አንድ ኮከብ ከ{max}}one{# ኮከብ ከ{max}}other{# ኮከቦች ከ{max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"በሂደት ላይ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"... በመጠቀም ድርጊቱን አጠናቅ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sን ተጠቅመው እርምጃ ያጠናቅቁ"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"የክልል ምርጫ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"የቋንቋ ስም ይተይቡ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"የተጠቆሙ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"በአስተያየት የተጠቆሙ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"በአስተያየት የተጠቆሙ ቋንቋዎች"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"በአስተያየት የተጠቆሙ ክልሎች"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ሁሉም ቋንቋዎች"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ይፈቀድለት?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"የአንድ ጊዜ መዳረሻን ፍቀድ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"አትፍቀድ"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"የመሣሪያ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ምን እንደሚከሰት ይመዘግባሉ። መተግበሪያዎች ችግሮችን ለማግኘት እና ለማስተካከል እነዚህን ምዝግብ ማስታወሻዎች መጠቀም ይችላሉ።\n\nአንዳንድ ምዝግብ ማስታወሻዎች ሚስጥራዊነት ያለው መረጃ ሊይዙ ይችላሉ፣ ስለዚህ የሚያምኗቸውን መተግበሪያዎች ብቻ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርሱ ይፍቀዱላቸው። \n\nይህ መተግበሪያ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ካልፈቀዱለት አሁንም የራሱን ምዝግብ ማስታወሻዎች መድረስ ይችላል። የእርስዎ መሣሪያ አምራች አሁንም አንዳንድ ምዝግብ ማስታወሻዎችን ወይም መረጃዎችን በመሣሪያዎ ላይ ሊደርስ ይችላል።"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ዳግም አታሳይ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> የ<xliff:g id="APP_2">%2$s</xliff:g> ቁራጮችን ማሳየት ይፈልጋል"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"አርትዕ"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ንቁ መተግበሪያዎችን ይፈትሹ"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"የስልኩን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ጡባዊውን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"ዥረት በመልቀቅ ላይ ሳለ ይህ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
     <string name="system_locale_title" msgid="711882686834677268">"የሥርዓት ነባሪ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ካርድ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 1ede739..82fc943 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -609,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"تم إجراء عدد كبير جدًا من المحاولات. لذا تم إيقاف جهاز استشعار بصمات الإصبع."</string>
+    <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>
@@ -638,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>
@@ -1171,8 +1172,7 @@
     <string name="not_checked" msgid="7972320087569023342">"لم يتم وضع علامة"</string>
     <string name="selected" msgid="6614607926197755875">"محدّد"</string>
     <string name="not_selected" msgid="410652016565864475">"غير محدّد"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{نجمة واحدة من {max}}zero{# نجمة من {max}}two{نجمتان من {max}}few{# نجوم من {max}}many{# نجمة من {max}}other{# نجمة من {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"قيد التقدّم"</string>
     <string name="whichApplication" msgid="5432266899591255759">"إكمال الإجراء باستخدام"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏إكمال الإجراء باستخدام %1$s"</string>
@@ -1426,7 +1426,7 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"جارٍ إخراج <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"عدم الإزالة"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"إعداد"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"إلغاء"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"إخراج"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"استكشاف"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"تبديل جهاز إخراج الصوت"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> مفقود"</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>
@@ -1929,8 +1929,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"تفضيل المنطقة"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"اكتب اسم اللغة"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"اللغات المقترَحة"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"الاقتراحات"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"اللغات المُقترَحة"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"المناطق المُقترَحة"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"جميع اللغات"</string>
@@ -2055,8 +2054,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"هل تريد السماح لتطبيق <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> بالوصول إلى جميع سجلّات الجهاز؟"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"السماح بالوصول إلى السجلّ لمرة واحدة"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"عدم السماح"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ترصد سجلّات الجهاز ما يحدث على جهازك. يمكن أن تستخدم التطبيقات هذه السجلّات لتحديد المشاكل وحلها.\n\nقد تحتوي بعض السجلّات على معلومات حساسة، ولذلك يجب عدم السماح بالوصول إلى جميع سجلّات الجهاز إلا للتطبيقات التي تثق بها. \n\nإذا لم تسمح بوصول هذا التطبيق إلى جميع سجلّات الجهاز، يظل بإمكان التطبيق الوصول إلى سجلّاته. ويظل بإمكان الشركة المصنِّعة لجهازك الوصول إلى بعض السجلّات أو المعلومات المتوفّرة على جهازك."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"عدم الإظهار مرة أخرى"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"يريد تطبيق <xliff:g id="APP_0">%1$s</xliff:g> عرض شرائح تطبيق <xliff:g id="APP_2">%2$s</xliff:g>."</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"تعديل"</string>
@@ -2297,8 +2295,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"التحقّق من التطبيقات النشطة"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"يتعذّر الوصول إلى كاميرا الهاتف من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"يتعذّر الوصول إلى كاميرا الجهاز اللوحي من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"لا يمكن الوصول إلى هذا المحتوى أثناء البث. بدلاً من ذلك، جرِّب استخدام هاتفك."</string>
     <string name="system_locale_title" msgid="711882686834677268">"الإعداد التلقائي للنظام"</string>
     <string name="default_card_name" msgid="9198284935962911468">"‏رقم البطاقة ‎<xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index edc0979..93957e5 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"অত্যধিক প্ৰয়াস। ফিংগাৰপ্ৰিণ্ট ছেন্সৰ অক্ষম কৰা হ’ল।"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"টিক চিহ্ন দিয়া হোৱা নাই"</string>
     <string name="selected" msgid="6614607926197755875">"বাছনি কৰা"</string>
     <string name="not_selected" msgid="410652016565864475">"বাছনি কৰা হোৱা নাই"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} টাৰ ভিতৰত ১ টা তৰা}one{{max} টাৰ ভিতৰত # টা তৰা}other{{max} টাৰ ভিতৰত # টা তৰা}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"চলি আছে"</string>
     <string name="whichApplication" msgid="5432266899591255759">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যৱহাৰ কৰি কাৰ্যটো সম্পূৰ্ণ কৰক"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"অঞ্চলৰ অগ্ৰাধিকাৰ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ভাষাৰ নাম লিখক"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"প্ৰস্তাৱিত"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"পৰামৰ্শিত"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"পৰামৰ্শিত ভাষাসমূহ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"চুপাৰিছ কৰা অঞ্চলসমূহ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"সকলো ভাষা"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ক আটাইবোৰ ডিভাইচৰ লগ এক্সেছ কৰাৰ অনুমতি প্ৰদান কৰিবনে?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"কেৱল এবাৰ এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি নিদিব"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"আপোনাৰ ডিভাইচত কি কি ঘটে সেয়া ডিভাইচ লগে ৰেকৰ্ড কৰে। এপ্‌সমূহে সমস্যা বিচাৰিবলৈ আৰু সমাধান কৰিবলৈ এই লগসমূহ ব্যৱহাৰ কৰিব পাৰে।\n\nকিছুমান লগত সংবেদনশীল তথ্য থাকিব পাৰে, গতিকে কেৱল আপুনি বিশ্বাস কৰা এপকহে আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি দিয়ক। \n\nআপুনি যদি এই এপ্‌টোক আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি নিদিয়ে, তথাপিও ই নিজৰ লগসমূহ এক্সেছ কৰিব পাৰিব। আপোনাৰ ডিভাইচৰ নিৰ্মাতাই তথাপিও হয়তো আপোনাৰ ডিভাইচটোত থকা কিছু লগ অথবা তথ্য এক্সেছ কৰিব পাৰিব।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"পুনৰ নেদেখুৱাব"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>এ <xliff:g id="APP_2">%2$s</xliff:g>ৰ অংশ দেখুওৱাব খুজিছে"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"সম্পাদনা কৰক"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"সক্ৰিয় এপ্‌সমূহ পৰীক্ষা কৰক"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা ফ’নটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা টেবলেটটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"ষ্ট্ৰীম কৰি থকাৰ সময়ত এইটো এক্সেছ কৰিব নোৱাৰি। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ছিষ্টেম ডিফ’ল্ট"</string>
     <string name="default_card_name" msgid="9198284935962911468">"কাৰ্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 04e7024..c4f3d75 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Həddindən çox cəhd. Barmaq izi sensoru deaktiv edilib."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"yoxlanılmayıb"</string>
     <string name="selected" msgid="6614607926197755875">"seçilib"</string>
     <string name="not_selected" msgid="410652016565864475">"seçilməyib"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1/{max} ulduz}other{#/{max} ulduz}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"davam edir"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Əməliyyatı tamamlayın:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s istifadə edərək əməliyyatı tamamlayı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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Region seçimi"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Dil adını daxil edin"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Təklif edilmiş"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Təklif edilib"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Təklif edilən dillər"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Təklif edilən regionlar"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Bütün dillər"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> tətbiqinin bütün cihaz qeydlərinə girişinə icazə verilsin?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Birdəfəlik girişə icazə verin"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"İcazə verməyin"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Cihaz qeydləri cihazınızda baş verənləri qeyd edir. Tətbiqlər problemləri tapmaq və həll etmək üçün bu qeydlərdən istifadə edə bilər.\n\nBəzi qeydlərdə həssas məlumatlar ola bilər, ona görə də yalnız etibar etdiyiniz tətbiqlərin bütün cihaz qeydlərinə giriş etməsinə icazə verin. \n\nBu tətbiqin bütün cihaz qeydlərinə girişinə icazə verməsəniz, o, hələ də öz qeydlərinə giriş edə bilər. Cihaz istehsalçınız hələ də cihazınızda bəzi qeydlərə və ya məlumatlara giriş edə bilər."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daha göstərməyin"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> tətbiqindən bölmələr göstərmək istəyir"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Redaktə edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index ba07550..bf9c57b 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -606,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Previše pokušaja. Senzor za otisak prsta je onemogućen."</string>
+    <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>
@@ -635,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>
@@ -1168,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
     <string name="selected" msgid="6614607926197755875">"izabrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nije izabrano"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Jedna zvezdica od {max}}one{# zvezdica od {max}}few{# zvezdice od {max}}other{# zvezdica od {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"u toku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dovrši radnju preko"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</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>
@@ -1926,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Podešavanje regiona"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Predloženi"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predloženo"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Predloženi jezici"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Predloženi regioni"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Svi jezici"</string>
@@ -2052,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Želite da dozvolite aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim evidencijama uređaja?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dozvoli jednokratan pristup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dozvoli"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Evidencije uređaja registruju šta se dešava na uređaju. Aplikacije mogu da koriste te evidencije da bi pronašle i rešile probleme.\n\nNeke evidencije mogu da sadrže osetljive informacije, pa pristup svim evidencijama uređaja treba da dozvoljavate samo aplikacijama u koje imate poverenja. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim evidencijama uređaja, ona i dalje može da pristupa sopstvenim evidencijama. Proizvođač uređaja će možda i dalje moći da pristupa nekim evidencijama ili informacijama na uređaju."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Izmeni"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index bf8e85f..1af3c7d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Занадта шмат спроб. Сканер адбіткаў пальцаў выключаны."</string>
+    <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 +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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не пазначана"</string>
     <string name="selected" msgid="6614607926197755875">"выбраны"</string>
     <string name="not_selected" msgid="410652016565864475">"не выбраны"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Адна зорка з {max}}one{# зорка з {max}}few{# зоркі з {max}}many{# зорак з {max}}other{# зоркі з {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"выконваецца"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Завяршыць дзеянне з дапамогай"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завяршыць дзеянне з дапамогай %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Параметры рэгіёна"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Увядзіце назву мовы"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Прапанаваныя"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Прапанавана"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Прапанаваныя мовы"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Прапанаваныя рэгіёны"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Усе мовы"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Дазволіць праграме \"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>\" мець доступ да ўсіх журналаў прылады?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дазволіць аднаразовы доступ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дазваляць"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Журналы прылад запісваюць усё, што адбываецца на вашай прыладзе. Праграмы выкарыстоўваюць гэтыя журналы для пошуку і выпраўлення памылак.\n\nУ некаторых журналах можа ўтрымлівацца канфідэнцыяльная інфармацыя, таму давайце доступ да ўсіх журналаў прылады толькі тым праграмам, якім вы давяраеце. \n\nКалі вы не дасце гэтай праграме доступу да ўсіх журналаў прылад, у яе ўсё роўна застанецца доступ да ўласных журналаў. Для вытворцы вашай прылады будуць даступнымі некаторыя журналы і інфармацыя на вашай прыладзе."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больш не паказваць"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Праграма <xliff:g id="APP_0">%1$s</xliff:g> запытвае дазвол на паказ зрэзаў праграмы <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Рэдагаваць"</string>
@@ -2295,8 +2293,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Праверце актыўныя праграмы"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не ўдалося атрымаць доступ да камеры тэлефона з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не ўдалося атрымаць доступ да камеры планшэта з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Не ўдаецца атрымаць доступ у час перадачы плынню. Паспрабуйце скарыстаць тэлефон."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Стандартная сістэмная налада"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 3ad22fa..4ae1f21 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Твърде много опити. Сензорът за отпечатъци е деактивиран."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"без отметка"</string>
     <string name="selected" msgid="6614607926197755875">"избрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не е избрано"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Една от {max} звезди}other{# от {max} звезди}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"в ход"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Изпълняване на действието чрез"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завършване на действието посредством %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Предпочитание за региона"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Въведете име на език"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Предложени"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Предложени"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Предложени езици"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Предложени региони"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Всички езици"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Да се разреши ли на <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> достъп до всички регистрационни файлове за устройството?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Разрешаване на еднократен достъп"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Забраняване"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"В регистрационните файлове за устройството се записва какво се извършва на него. Приложенията могат да използват тези регистрационни файлове, за да откриват и отстраняват проблеми.\n\nНякои регистрационни файлове за устройството може да съдържат поверителна информация, затова разрешавайте достъп до всички тях само на приложения, на които имате доверие. \n\nАко не разрешите на това приложение достъп до всички регистрационни файлове за устройството, то пак може да осъществява достъп до собствените си регистрационни файлове. Производителят на устройството пак може да има достъп до някои регистрационни файлове или информация на устройството ви."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Да не се показва пак"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> иска да показва части от <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Редактиране"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 8a3a3e4..2aac0c9 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"বহুবার চেষ্টা করেছেন। আঙ্গুলের ছাপ নেওয়ার সেন্সর অক্ষম করা হয়েছে।"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"টিকচিহ্ন দেওয়া নেই"</string>
     <string name="selected" msgid="6614607926197755875">"বেছে নেওয়া হয়েছে"</string>
     <string name="not_selected" msgid="410652016565864475">"বেছে নেওয়া হয়নি"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}টির মধ্যে একটি স্টার}one{#টির মধ্যে {max}টি স্টার}other{#টির মধ্যে {max}টি স্টার}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"কাজ চলছে"</string>
     <string name="whichApplication" msgid="5432266899591255759">"এটি ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"পছন্দের অঞ্চল"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ভাষার নাম লিখুন"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"প্রস্তাবিত"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"সাজেস্ট করা অঞ্চল"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"সাজেস্ট করা ভাষা"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"সাজেস্ট করা অঞ্চল"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"সকল ভাষা"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেসের অনুমতি দিতে চান?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"এককালীন অ্যাক্সেসের অনুমতি দিন"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি দেবেন না"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই সব ডিভাইসের লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারকও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"আর দেখতে চাই না"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"এডিট করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 8429ebb..3c87b0d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -606,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Previše pokušaja. Senzor za otisak prsta je onemogućen."</string>
+    <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>
@@ -635,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>
@@ -1168,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
     <string name="selected" msgid="6614607926197755875">"odabrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nije odabrano"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Jedna zvjezdica od {max}}one{# zvjezdica od {max}}few{# zvjezdice od {max}}other{# zvjezdica od {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"u toku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Završite radnju pomoću aplikacije"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string>
@@ -1427,7 +1427,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"Istraži"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Prebacite izlaz"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> nedostaje"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"Ponovo ubacite uređaj"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"Ponovo umetnite uređaj"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"Premješta se <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Premještanje podataka"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"Prijenos sadržaja je završen"</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>
@@ -1926,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Izbor regije"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Upišite ime jezika"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Predloženo"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predloženo"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Predloženi jezici"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Predložene regije"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Svi jezici"</string>
@@ -2052,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Dozvoliti aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim zapisnicima uređaja?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dozvoli jednokratan pristup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dozvoliti"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Zapisnici uređaja bilježe šta se dešava na uređaju. Aplikacije mogu koristiti te zapisnike da pronađu i isprave probleme.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, zato pristup svim zapisnicima uređaja dozvolite samo aplikacijama kojima vjerujete. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač uređaja će možda i dalje biti u stanju pristupiti nekim zapisnicima ili podacima na uređaju."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d9a6883..317c004 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"S\'han fet massa intents. S\'ha desactivat el sensor d\'empremtes digitals."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"no seleccionat"</string>
     <string name="selected" msgid="6614607926197755875">"seleccionat"</string>
     <string name="not_selected" msgid="410652016565864475">"no seleccionat"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 estrella de {max}}other{# estrelles de {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"en curs"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completa l\'acció mitjançant"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completa l\'acció amb %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferència de regió"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Escriu el nom de l\'idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggerits"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Recomanades"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomes suggerits"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regions suggerides"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Tots els idiomes"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Vols permetre que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> accedeixi a tots els registres del dispositiu?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permet l\'accés únic"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permetis"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Els registres del dispositiu inclouen informació sobre tot allò que passa al teu dispositiu. Les aplicacions poden utilitzar aquests registres per detectar i corregir problemes.\n\nÉs possible que alguns registres continguin informació sensible; per això només has de donar-hi accés a les aplicacions de confiança. \n\nEncara que no permetis que aquesta aplicació pugui accedir a tots els registres del dispositiu, podrà accedir als seus propis registres. És possible que el fabricant del dispositiu també tingui accés a alguns registres o a informació del teu dispositiu."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No tornis a mostrar"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vol mostrar porcions de l\'aplicació <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edita"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consulta les aplicacions actives"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No es pot accedir a la càmera del telèfon des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No es pot accedir a la càmera de la tauleta des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"No s\'hi pot accedir mentre s\'està reproduint en continu. Prova-ho al telèfon."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Valor predeterminat del sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARGETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 601af14..cbd2df6 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Příliš mnoho pokusů. Snímač otisků prstů byl deaktivován."</string>
+    <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>
@@ -636,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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nevybráno"</string>
     <string name="selected" msgid="6614607926197755875">"vybráno"</string>
     <string name="not_selected" msgid="410652016565864475">"nevybráno"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Jedna hvězdička z {max}}few{# hvězdičky z {max}}many{# hvězdičky z {max}}other{# hvězdiček z {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"probíhá"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončit akci pomocí aplikace"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončit akci pomocí aplikace %1$s"</string>
@@ -1428,7 +1428,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"Otevřít"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Přepnout výstup"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> chybí"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"Znovu vložte zařízení"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"Vložte zařízení znovu"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"Přesouvání aplikace <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Probíhá přesun dat"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"Přenos obsahu je dokončen"</string>
@@ -1567,7 +1567,7 @@
     <string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s – %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s – %3$s"</string>
     <string name="storage_internal" msgid="8490227947584914460">"Interní sdílené úložiště"</string>
-    <string name="storage_sd_card" msgid="3404740277075331881">"Karta SD"</string>
+    <string name="storage_sd_card" msgid="3404740277075331881">"SD karta"</string>
     <string name="storage_sd_card_label" msgid="7526153141147470509">"SD karta <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="448030813201444573">"Jednotka USB"</string>
     <string name="storage_usb_drive_label" msgid="6631740655876540521">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferovaná oblast"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Zadejte název jazyka"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Navrhované"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Navrženo"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Navrhované jazyky"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Navrhované oblasti"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Všechny jazyky"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Povolit aplikaci <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> přístup ke všem protokolům zařízení?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Povolit jednorázový přístup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovolovat"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Do protokolů zařízení se zaznamenává, co se na zařízení děje. Aplikace tyto protokoly mohou používat k vyhledání a odstranění problémů.\n\nNěkteré protokoly mohou zahrnovat citlivé údaje. Přístup k protokolům zařízení proto povolte pouze aplikacím, kterým důvěřujete. \n\nPokud této aplikaci nepovolíte přístup ke všem protokolům zařízení, bude mít stále přístup ke svým vlastním protokolům. Výrobce zařízení může mít stále přístup k některým protokolům nebo informacím na vašem zařízení."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Příště nezobrazovat"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikace <xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovat ukázky z aplikace <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Upravit"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 06b1336..083c42c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Du har brugt for mange forsøg. Fingeraftrykslæseren er deaktiveret."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"slået fra"</string>
     <string name="selected" msgid="6614607926197755875">"valgt"</string>
     <string name="not_selected" msgid="410652016565864475">"ikke valgt"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{En stjerne ud af {max}}one{# stjerne ud af {max}}other{# stjerner ud af {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"i gang"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Brug"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Gennemfør handling ved hjælp af %1$s"</string>
@@ -1566,7 +1566,7 @@
     <string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
     <string name="storage_internal" msgid="8490227947584914460">"Intern delt lagerplads"</string>
     <string name="storage_sd_card" msgid="3404740277075331881">"SD-kort"</string>
-    <string name="storage_sd_card_label" msgid="7526153141147470509">"SD-kort fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
+    <string name="storage_sd_card_label" msgid="7526153141147470509">"SD-kort (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb_drive" msgid="448030813201444573">"USB-drev"</string>
     <string name="storage_usb_drive_label" msgid="6631740655876540521">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="2391213347883616886">"USB-lager"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Områdeindstilling"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Angiv sprog"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Foreslået"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Forslag"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Foreslåede sprog"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Foreslåede områder"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Alle sprog"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Vil du give <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> adgang til alle enhedslogs?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tillad engangsadgang"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillad ikke"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Enhedslogs registrerer, hvad der sker på din enhed. Apps kan bruge disse logs til at finde og løse problemer.\n\nNogle logs kan indeholde følsomme oplysninger, så giv kun apps, du har tillid til, adgang til alle enhedslogs. \n\nSelvom du ikke giver denne app adgang til alle enhedslogs, kan den stadig tilgå sine egne logs. Producenten af din enhed kan muligvis fortsat tilgå visse logs eller oplysninger på din enhed."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vis ikke igen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Rediger"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tjek aktive apps"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kameraet på din telefon kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kameraet på din tablet kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Der er ikke adgang til dette indhold under streaming. Prøv på din telefon i stedet."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c511992..fc8eadaf 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Zu viele Versuche. Der Fingerabdrucksensor wurde deaktiviert."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"deaktiviert"</string>
     <string name="selected" msgid="6614607926197755875">"ausgewählt"</string>
     <string name="not_selected" msgid="410652016565864475">"nicht ausgewählt"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Einer von {max} Sternen}other{# von {max} Sternen}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"Noch nicht abgeschlossen"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Aktion durchführen mit"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Aktion mit %1$s abschließen"</string>
@@ -1249,10 +1249,8 @@
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Apps werden gestartet..."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Start wird abgeschlossen..."</string>
     <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du hast die Ein-/Aus-Taste gedrückt — damit wird der Bildschirm ausgeschaltet.\n\nTippe die Taste leicht an, um deinen Fingerabdruck einzurichten."</string>
-    <!-- no translation found for fp_power_button_enrollment_title (8997641910928785172) -->
-    <skip />
-    <!-- no translation found for fp_power_button_enrollment_button_text (8351290204990805109) -->
-    <skip />
+    <string name="fp_power_button_enrollment_title" msgid="8997641910928785172">"Tippen, um Display auszuschalten"</string>
+    <string name="fp_power_button_enrollment_button_text" msgid="8351290204990805109">"Display ausschalten"</string>
     <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Mit der Fingerabdruckprüfung fortfahren?"</string>
     <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du hast die Ein-/Aus-Taste gedrückt — damit wird der Bildschirm ausgeschaltet.\n\nTippe die Taste leicht an, um mit deinem Fingerabdruck deine Identität zu bestätigen."</string>
     <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Ausschalten"</string>
@@ -1613,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>
@@ -1927,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Region auswählen"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Sprache eingeben"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Vorschläge"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Vorschläge"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Vorgeschlagene Sprachen"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Vorgeschlagene Regionen"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Alle Sprachen"</string>
@@ -2053,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> den Zugriff auf alle Geräteprotokolle erlauben?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Einmaligen Zugriff zulassen"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nicht zulassen"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"In Geräteprotokollen wird aufgezeichnet, welche Aktionen auf deinem Gerät ausgeführt werden. Apps können diese Protokolle verwenden, um Probleme zu finden und zu beheben.\n\nEinige Protokolle enthalten unter Umständen vertrauliche Informationen, daher solltest du nur vertrauenswürdigen Apps den Zugriff auf alle Geräteprotokolle erlauben. \n\nWenn du dieser App keinen Zugriff auf alle Geräteprotokolle gewährst, kann sie trotzdem auf ihre eigenen Protokolle zugreifen. Dein Gerätehersteller hat möglicherweise auch Zugriff auf einige Protokolle oder Informationen auf deinem Gerät."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nicht mehr anzeigen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> möchte Teile von <xliff:g id="APP_2">%2$s</xliff:g> anzeigen"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Bearbeiten"</string>
@@ -2295,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Aktive Apps prüfen"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Zugriff auf die Kamera des Smartphones über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Zugriff auf die Kamera des Tablets über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Während des Streamings ist kein Zugriff möglich. Versuch es stattdessen auf deinem Smartphone."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Standardeinstellung des Systems"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index c73f6db..c76b2b0 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Πάρα πολλές προσπάθειες. Ο αισθητήρας δακτυλικών αποτυπωμάτων απενεργοποιήθηκε."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"μη επιλεγμένο"</string>
     <string name="selected" msgid="6614607926197755875">"επιλεγμένο"</string>
     <string name="not_selected" msgid="410652016565864475">"μη επιλεγμένο"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Ένα αστέρι από {max}}other{# αστέρια από {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"σε εξέλιξη"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Ολοκληρωμένη ενέργεια με χρήση %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Προτίμηση περιοχής"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Εισαγ. όνομα γλώσσας"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Προτεινόμενες"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Προτεινόμενα"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Προτεινόμενες γλώσσες"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Προτεινόμενες περιοχές"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Όλες οι γλώσσες"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Να επιτρέπεται στο <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> η πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής;"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Να επιτρέπεται η πρόσβαση για μία φορά"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Να μην επιτραπεί"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Να μην εμφανισ. ξανά"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Η εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> θέλει να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Επεξεργασία"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cd68709..8591467 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -605,7 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{One star out of {max}}other{# stars out of {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Suggested languages"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Suggested regions"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index b164a73..08097a5 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -605,7 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not checked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{One star out of {max}}other{# stars out of {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Suggested languages"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Suggested regions"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 475073e..bf82587 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -605,7 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{One star out of {max}}other{# stars out of {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Suggested languages"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Suggested regions"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index af3c7f6..110e68f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -605,7 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"Fingerprint operation cancelled."</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Fingerprint operation cancelled by user."</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Too many attempts. Try again later."</string>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Too many attempts. Fingerprint sensor disabled."</string>
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"Too many attempts. Use screen lock instead."</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Try again."</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"No fingerprints enrolled."</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"This device does not have a fingerprint sensor."</string>
@@ -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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
     <string name="selected" msgid="6614607926197755875">"selected"</string>
     <string name="not_selected" msgid="410652016565864475">"not selected"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{One star out of {max}}other{# stars out of {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"In progress"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Region preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Type language name"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggested"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggested"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Suggested languages"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Suggested regions"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"All languages"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Allow <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> to access all device logs?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 6ed6dd8..ddb93a8 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -605,7 +605,7 @@
     <string name="fingerprint_error_canceled" msgid="540026881380070750">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎Fingerprint operation canceled.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎Fingerprint operation canceled by user.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_lockout" msgid="7853461265604738671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎Too many attempts. Try again later.‎‏‎‎‏‎"</string>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎Too many attempts. Fingerprint sensor disabled.‎‏‎‎‏‎"</string>
+    <string name="fingerprint_error_lockout_permanent" msgid="9060651300306264843">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎Too many attempts. Use screen lock instead.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎Try again.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‎No fingerprints enrolled.‎‏‎‎‏‎"</string>
     <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‏‏‎‎This device does not have a fingerprint sensor.‎‏‎‎‏‎"</string>
@@ -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>
@@ -1167,8 +1167,7 @@
     <string name="not_checked" msgid="7972320087569023342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎not checked‎‏‎‎‏‎"</string>
     <string name="selected" msgid="6614607926197755875">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‎‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎selected‎‏‎‎‏‎"</string>
     <string name="not_selected" msgid="410652016565864475">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎not selected‎‏‎‎‏‎"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‎One star out of ‎‏‎‎‏‏‎{max}‎‏‎‎‏‏‏‎‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‎# stars out of ‎‏‎‎‏‏‎{max}‎‏‎‎‏‏‏‎‎‏‎‎‏‎}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‏‎‎‎‏‎in progress‎‏‎‎‏‎"</string>
     <string name="whichApplication" msgid="5432266899591255759">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎Complete action using‎‏‎‎‏‎"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎Complete action using %1$s‎‏‎‎‏‎"</string>
@@ -1611,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>
@@ -2050,8 +2049,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‎‎‏‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ to access all device logs?‎‏‎‎‏‎"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎Allow one-time access‎‏‎‎‏‎"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎Don’t allow‎‏‎‎‏‎"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎Device logs record what happens on your device. Apps can use these logs to find and fix issues.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Some logs may contain sensitive info, so only allow apps you trust to access all device logs. ‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎If you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device.‎‏‎‎‏‎"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‎Don’t show again‎‏‎‎‏‎"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎ wants to show ‎‏‎‎‏‏‎<xliff:g id="APP_2">%2$s</xliff:g>‎‏‎‎‏‏‏‎ slices‎‏‎‎‏‎"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎Edit‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 269eb18..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Realizaste demasiados intentos. Se inhabilitó el sensor de huellas dactilares."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1425,7 +1426,7 @@
     <string name="ext_media_unmount_action" msgid="966992232088442745">"Expulsar"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"Explorar"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Cambiar salida"</string>
-    <string name="ext_media_missing_title" msgid="3209472091220515046">"No se encuentra dispositivo <xliff:g id="NAME">%s</xliff:g>."</string>
+    <string name="ext_media_missing_title" msgid="3209472091220515046">"Falta <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"Vuelve a insertar dispositivo"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"Transfiriendo la aplicación <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Transfiriendo los datos"</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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Nombre del idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerencias"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regiones sugeridas"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Todos los idiomas"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"¿Quieres permitir que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos los registros del dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acceso por única vez"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Los registros del dispositivo permiten documentar lo que sucede en él. Las apps pueden usar estos registros para encontrar y solucionar problemas.\n\nEs posible que algunos registros del dispositivo contengan información sensible, por lo que solo debes permitir que accedan a todos ellos las apps que sean de tu confianza. \n\nSi no permites que esta app acceda a todos los registros del dispositivo, aún puede acceder a sus propios registros. Además, es posible que el fabricante del dispositivo acceda a algunos registros o información en tu dispositivo."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2112,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 de87a54..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Demasiados intentos. Se ha inhabilitado el sensor de huellas digitales."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferencia de región"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Nombre de idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerencias"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regiones sugeridas"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Todos los idiomas"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"¿Permitir que <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos los registros del dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir el acceso una vez"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Los registros del dispositivo documentan lo que sucede en tu dispositivo. Las aplicaciones pueden usar estos registros para encontrar y solucionar problemas.\n\nComo algunos registros pueden contener información sensible, es mejor que solo permitas que accedan a ellos las aplicaciones en las que confíes. \n\nAunque no permitas que esta aplicación acceda a todos los registros del dispositivo, aún podrá acceder a sus propios registros. El fabricante de tu dispositivo aún puede acceder a algunos registros o información de tu dispositivo."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2112,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>
@@ -2293,8 +2292,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Consultar aplicaciones activas"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del teléfono desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara del tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una emisión. Prueba en tu teléfono."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 54de367..fe7549e 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Liiga palju katseid. Sõrmejäljeandur on keelatud."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"märkimata"</string>
     <string name="selected" msgid="6614607926197755875">"valitud"</string>
     <string name="not_selected" msgid="410652016565864475">"pole valitud"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 tärn {max}-st}other{# tärni {max}-st}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"pooleli"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Lõpetage toiming rakendusega"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Toimingu lõpetamine, kasutades rakendust %1$s"</string>
@@ -1422,8 +1422,8 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"Üksuse <xliff:g id="NAME">%s</xliff:g> väljutamine …"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Ärge eemaldage"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"Seadistus"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"Eemaldamine"</string>
-    <string name="ext_media_browse_action" msgid="344865351947079139">"Avastamine"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"Eemalda"</string>
+    <string name="ext_media_browse_action" msgid="344865351947079139">"Avasta"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Vahetage väljundit"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"Üksust <xliff:g id="NAME">%s</xliff:g> pole"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"Sisestage seade uuesti"</string>
@@ -1566,9 +1566,9 @@
     <string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
     <string name="storage_internal" msgid="8490227947584914460">"Sisemine jagatud mäluruum"</string>
     <string name="storage_sd_card" msgid="3404740277075331881">"SD-kaart"</string>
-    <string name="storage_sd_card_label" msgid="7526153141147470509">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> SD-kaart"</string>
+    <string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-kaart"</string>
     <string name="storage_usb_drive" msgid="448030813201444573">"USB-ketas"</string>
-    <string name="storage_usb_drive_label" msgid="6631740655876540521">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
+    <string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
     <string name="storage_usb" msgid="2391213347883616886">"USB-mäluseade"</string>
     <string name="extract_edit_menu_button" msgid="63954536535863040">"Muuda"</string>
     <string name="data_usage_warning_title" msgid="9034893717078325845">"Andmekasutuse hoiatus"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Piirkonnaeelistus"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Sisestage keele nimi"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Soovitatud"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Soovitatud"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Soovitatud keeled"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Soovitatud piirkonnad"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Kõik keeled"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Kas anda rakendusele <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> juurdepääs kõigile seadmelogidele?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Luba ühekordne juurdepääs"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ära luba"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Seadmelogid jäädvustavad, mis teie seadmes toimub. Rakendused saavad neid logisid kasutada probleemide tuvastamiseks ja lahendamiseks.\n\nMõned logid võivad sisaldada tundlikku teavet, seega lubage juurdepääs kõigile seadmelogidele ainult rakendustele, mida usaldate. \n\nKui te ei luba sellel rakendusel kõigile seadmelogidele juurde pääseda, pääseb see siiski juurde oma logidele. Teie seadme tootja võib teie seadmes siiski teatud logidele või teabele juurde pääseda."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ära kuva uuesti"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Rakendus <xliff:g id="APP_0">%1$s</xliff:g> soovib näidata rakenduse <xliff:g id="APP_2">%2$s</xliff:g> lõike"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Muuda"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vaadake aktiivseid rakendusi"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tahvelarvuti kaamerale juurde"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Sellele ei pääse voogesituse ajal juurde. Proovige juurde pääseda oma telefonis."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Süsteemi vaikeseade"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 25c6678..7f424ebd 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -52,7 +52,7 @@
     <string name="imei" msgid="2157082351232630390">"IMEIa"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
     <string name="ClipMmi" msgid="4110549342447630629">"Sarrerako deien identifikazio-zerbitzua"</string>
-    <string name="ClirMmi" msgid="6752346475055446417">"Ezkutatu irteerako deitzailearen IDa"</string>
+    <string name="ClirMmi" msgid="6752346475055446417">"Ezkutatu irteerako deitzailearen identitatea"</string>
     <string name="ColpMmi" msgid="4736462893284419302">"Konektatutako linearen IDa"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"Konektatutako linearen ID murriztapena"</string>
     <string name="CfMmi" msgid="8390012691099787178">"Dei-desbideratzea"</string>
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Saiakera gehiegi egin dituzu. Desgaitu egin da hatz-marken sentsorea."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"markatu gabe"</string>
     <string name="selected" msgid="6614607926197755875">"hautatuta"</string>
     <string name="not_selected" msgid="410652016565864475">"hautatu gabe"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} izarretatik bat}other{{max} izarretatik #}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"abian"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Gauzatu ekintza hau erabilita:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Osatu ekintza %1$s erabiliz"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Lurralde-hobespena"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Adierazi hizkuntza"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Iradokitakoak"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Iradokitakoak"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Iradokitako hizkuntzak"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Iradokitako lurraldeak"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Hizkuntza guztiak"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Gailuko erregistro guztiak atzitzeko baimena eman nahi diozu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aplikazioari?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Eman behin erabiltzeko baimena"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ez eman baimenik"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Gailuko erregistroetan gailuan gertatzen den guztia gordetzen da. Arazoak bilatu eta konpontzeko erabil ditzakete aplikazioek erregistro horiek.\n\nBaliteke erregistro batzuek kontuzko informazioa edukitzea. Beraz, eman gailuko erregistro guztiak atzitzeko baimena fidagarritzat jotzen dituzun aplikazioei bakarrik. \n\nNahiz eta gailuko erregistro guztiak atzitzeko baimena ez eman aplikazio honi, aplikazioak hari dagozkion erregistroak atzitu ahalko ditu. Gainera, baliteke gailuaren fabrikatzaileak gailuko erregistro edo datu batzuk atzitu ahal izatea."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ez erakutsi berriro"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> aplikazioak <xliff:g id="APP_2">%2$s</xliff:g> aplikazioaren zatiak erakutsi nahi ditu"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index f59c2e1..83821a3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"تلاش‌های بسیاری زیادی انجام شده است. حسگر اثر انگشت غیرفعال شد."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"بدون علامت"</string>
     <string name="selected" msgid="6614607926197755875">"انتخاب شده"</string>
     <string name="not_selected" msgid="410652016565864475">"انتخاب نشده"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{یک ستاره از {max} ستاره}one{# ستاره از {max} ستاره}other{# ستاره از {max} ستاره}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"درحال انجام"</string>
     <string name="whichApplication" msgid="5432266899591255759">"تکمیل کنش بااستفاده از"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏تکمیل کنش بااستفاده از %1$s"</string>
@@ -1422,7 +1422,7 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"درحال بیرون راندن <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"جدا نکنید"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"راه‌اندازی"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"بیرون راندن"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"خارج کردن"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"کاوش"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"تغییر خروجی"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> وجود ندارد"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"اولویت‌های منطقه"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"نام زبان را تایپ کنید"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"پیشنهادی"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"پیشنهادی"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"زبان‌های پیشنهادی"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"مناطق پیشنهادی"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"همه زبان‌ها"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"به <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> اجازه می‌دهید به همه گزارش‌های دستگاه دسترسی داشته باشد؟"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"مجاز کردن دسترسی یک‌باره"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"اجازه ندادن"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"گزارش‌های دستگاه آنچه را در دستگاهتان رخ می‌دهد ثبت می‌کند. برنامه‌ها می‌توانند از این گزارش‌ها برای پیدا کردن مشکلات و رفع آن‌ها استفاده کنند.\n\nبرخی‌از گزارش‌ها ممکن است حاوی اطلاعات حساس باشند، بنابراین فقط به برنامه‌های مورداعتمادتان اجازه دسترسی به همه گزارش‌های دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارش‌های دستگاه دسترسی داشته باشد، همچنان می‌تواند به گزارش‌های خودش دسترسی داشته باشد. سازنده دستگاه نیز ممکن است همچنان بتواند به برخی‌از گزارش‌ها یا اطلاعات دستگاهتان دسترسی داشته باشد."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوباره نشان داده نشود"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> می‌خواهد تکه‌های <xliff:g id="APP_2">%2$s</xliff:g> را نشان دهد"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ویرایش"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 4f70e828..8798ffc 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Liian monta yritystä. Sormenjälkitunnistin poistettu käytöstä."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ei valittu"</string>
     <string name="selected" msgid="6614607926197755875">"valittu"</string>
     <string name="not_selected" msgid="410652016565864475">"ei valittu"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1/{max} tähteä}other{#/{max} tähteä}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"käynnissä"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Tee toiminto käyttäen sovellusta"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Suorita sovelluksella %1$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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Alueasetus"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Anna kielen nimi"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Ehdotukset"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ehdotettu"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Kieliehdotukset"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Alue-ehdotukset"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Kaikki kielet"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Saako <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> pääsyn kaikkiin laitelokeihin?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Salli kertaluonteinen pääsy"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Älä salli"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Laitteen tapahtumat tallentuvat laitelokeihin. Niiden avulla sovellukset voivat löytää ja korjata ongelmia.\n\nJotkin lokit voivat sisältää arkaluontoista tietoa, joten salli pääsy kaikkiin laitelokeihin vain sovelluksille, joihin luotat. \n\nJos et salli tälle sovellukselle pääsyä kaikkiin laitelokeihin, sillä on kuitenkin pääsy sen omiin lokeihin. Laitteen valmistajalla voi olla pääsy joihinkin lokeihin tai tietoihin laitteella."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Älä näytä uudelleen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> haluaa näyttää osia sovelluksesta <xliff:g id="APP_2">%2$s</xliff:g>."</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Muokkaa"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Tarkista aktiiviset sovellukset"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse puhelimen kameraan"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tabletin kameraan"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Sisältöön ei saa pääsyä striimauksen aikana. Kokeile striimausta puhelimella."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Järjestelmän oletusarvo"</string>
     <string name="default_card_name" msgid="9198284935962911468">"Kortti: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 6e9250f..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Trop de tentatives. Capteur d\'empreintes digitales désactivé."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1423,7 +1424,7 @@
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Ne pas retirer"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"Configurer"</string>
     <string name="ext_media_unmount_action" msgid="966992232088442745">"Éjecter"</string>
-    <string name="ext_media_browse_action" msgid="344865351947079139">"Découvrir"</string>
+    <string name="ext_media_browse_action" msgid="344865351947079139">"Explorer"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Changer de sortie"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"Mémoire de stockage <xliff:g id="NAME">%s</xliff:g> manquante"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"Insérez l\'appareil de nouveau"</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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Entrez la langue"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggestions"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggestions"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Langues suggérées"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Régions suggérées"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Toutes les langues"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à l\'ensemble des journaux de l\'appareil?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Autoriser un accès unique"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applications peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applications auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette application à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux. Le fabricant de votre appareil pourrait toujours être en mesure d\'accéder à certains journaux ou renseignements sur votre appareil."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
@@ -2112,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 da3c802..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Trop de tentatives. Lecteur d\'empreinte digitale désactivé."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1425,7 +1426,7 @@
     <string name="ext_media_unmount_action" msgid="966992232088442745">"Éjecter"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"Parcourir"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Changer de sortie"</string>
-    <string name="ext_media_missing_title" msgid="3209472091220515046">"Mémoire de stockage \"<xliff:g id="NAME">%s</xliff:g>\" manquante"</string>
+    <string name="ext_media_missing_title" msgid="3209472091220515046">"Support \"<xliff:g id="NAME">%s</xliff:g>\" manquant"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"Insérez le périphérique"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"Transfert de l\'application <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Déplacement des données en cours"</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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Préférences régionales"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Saisissez la langue"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggestions"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggestions"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Langues suggérées"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Régions suggérées"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Toutes les langues"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Autoriser <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> à accéder à tous les journaux de l\'appareil ?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Autoriser un accès unique"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Les journaux enregistrent ce qui se passe sur votre appareil. Les applis peuvent les utiliser pour rechercher et résoudre les problèmes.\n\nCertains journaux pouvant contenir des infos sensibles, autorisez uniquement les applis de confiance à accéder à tous les journaux de l\'appareil. \n\nSi vous refusez à cette appli l\'accès à tous les journaux de l\'appareil, elle a quand même accès aux siens. Le fabricant de l\'appareil peut accéder à certains journaux ou certaines infos sur votre appareil."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher des éléments de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
@@ -2112,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>
@@ -2293,8 +2292,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vérifier les applis actives"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Impossible d\'accéder à cela pendant le streaming. Essayez plutôt sur votre téléphone."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 0109665..ae29e50 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Demasiados intentos. Desactivouse o sensor de impresión dixital."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"non seleccionado"</string>
     <string name="selected" msgid="6614607926197755875">"elemento seleccionado"</string>
     <string name="not_selected" msgid="410652016565864475">"elemento non seleccionado"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 estrela de {max}}other{# estrelas de {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"en curso"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Completar a acción usando"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Completar a acción usando %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferencia de rexión"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Escribe o nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suxeridos"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Rexións suxeridas"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas suxeridos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Rexións suxeridas"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Queres permitir que a aplicación <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acceda a todos os rexistros do dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acceso unha soa vez"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non permitir"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os rexistros do dispositivo dan conta do que ocorre neste. As aplicacións poden usalos para buscar problemas e solucionalos.\n\nAlgúns poden conter información confidencial, polo que che recomendamos que só permitas que accedan a todos os rexistros do dispositivo as aplicacións nas que confíes. \n\nEsta aplicación pode acceder aos seus propios rexistros aínda que non lle permitas acceder a todos. É posible que o fabricante do dispositivo teña acceso a algúns rexistros ou á información do teu dispositivo."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non amosar outra vez"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quere mostrar fragmentos de aplicación de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Comprobar aplicacións activas"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Non se puido acceder á cámara do teléfono desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Non se puido acceder á cámara da tableta desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Non se puido acceder a este contido durante a reprodución en tempo real. Téntao desde o teléfono."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Opción predeterminada do sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARXETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 3bb7c38..36812e8 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ઘણા વધુ પ્રયત્નો. ફિંગરપ્રિન્ટ સેન્સર અક્ષમ કરવામાં આવ્યું છે."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ચેક કર્યું નથી"</string>
     <string name="selected" msgid="6614607926197755875">"પસંદ કરેલી"</string>
     <string name="not_selected" msgid="410652016565864475">"પસંદ નહીં કરેલી"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}માંથી એક સ્ટાર}one{{max}માંથી # સ્ટાર}other{{max}માંથી # સ્ટાર}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"પ્રક્રિયા ચાલુ છે"</string>
     <string name="whichApplication" msgid="5432266899591255759">"આના ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
@@ -1426,7 +1426,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"અન્વેષણ કરો"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"આઉટપુટ સ્વિચ કરો"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> ખૂટે છે"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"ફરીથી ઉપકરણ દાખલ કરો"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"ફરીથી ડિવાઇસ દાખલ કરો"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ખસેડી રહ્યાં છીએ"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"ડેટાને ખસેડી રહ્યાં છીએ"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"કન્ટેન્ટ ટ્રાન્સફર કરવાનું પૂર્ણ થયું"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"પ્રદેશ પસંદગી"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ભાષાનું નામ ટાઇપ કરો"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"સૂચવેલી ભાષા"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"સૂચવેલા"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"સૂચવેલી ભાષાઓ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"સૂચવેલા પ્રદેશો"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"બધી ભાષાઓ"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>ને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી આપવી છે?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"એક-વખતના ઍક્સેસની મંજૂરી આપો"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"મંજૂરી આપશો નહીં"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ફરીથી બતાવશો નહીં"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>એ <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવા માગે છે"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ફેરફાર કરો"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"સક્રિય ઍપ ચેક કરો"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ફોનના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ટૅબ્લેટના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"સ્ટ્રીમ કરતી વખતે આ ઍક્સેસ કરી શકાતું નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
     <string name="system_locale_title" msgid="711882686834677268">"સિસ્ટમ ડિફૉલ્ટ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"કાર્ડ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b8a0fc2..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"बहुत ज़्यादा कोशिशें. फ़िंगरप्रिंट सेंसर अक्षम है."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"बंद है"</string>
     <string name="selected" msgid="6614607926197755875">"चुना गया"</string>
     <string name="not_selected" msgid="410652016565864475">"नहीं चुना गया"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} में से एक स्टार}one{{max} में से # स्टार}other{{max} में से # स्टार}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"जारी है"</string>
     <string name="whichApplication" msgid="5432266899591255759">"इसका इस्तेमाल करके कार्रवाई को पूरा करें"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s का उपयोग करके कार्रवाई पूरी करें"</string>
@@ -1425,7 +1425,7 @@
     <string name="ext_media_unmount_action" msgid="966992232088442745">"निकालें"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"एक्सप्लोर करें"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"आउटपुट बदलें"</string>
-    <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> गुम है"</string>
+    <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> नहीं मिल रहा है"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"डिवाइस को दोबारा लगाएं"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> को ले जाया जा रहा है"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"डेटा ले जाया जा रहा है"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"क्षेत्र प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"भाषा का नाम लिखें"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"दिए गए सुझाव"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"सुझाए गए देश/इलाके"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"सुझाई गई भाषाएं"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"सुझाए गए इलाके"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"सभी भाषाएं"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"क्या <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> को डिवाइस लॉग का ऐक्सेस देना है?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक बार ऐक्सेस करने की अनुमति दें"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति न दें"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"डिवाइस लॉग में, आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें ठीक करने के लिए करते हैं.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह डिवाइस पर अपने लॉग को ऐक्सेस कर सकता है. डिवाइस को बनाने वाली कंपनी अब भी डिवाइस के कुछ लॉग या जानकारी को ऐक्सेस कर सकती है."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"फिर से न दिखाएं"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> के हिस्से (स्लाइस) दिखाना चाहता है"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"बदलाव करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index a638c7e..0a2702a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -606,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Senzor otiska prsta onemogućen je zbog previše pokušaja."</string>
+    <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>
@@ -635,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>
@@ -1168,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nije potvrđeno"</string>
     <string name="selected" msgid="6614607926197755875">"odabrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nije odabrano"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Jedna zvjezdica od {max}}one{# zvjezdica od {max}}few{# zvjezdice od {max}}other{# zvjezdica od {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"u tijeku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Radnju dovrši pomoću stavke"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršavanje radnje pomoću aplikacije %1$s"</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>
@@ -1926,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Postavke regije"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Unesite naziv jezika"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Predloženo"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predloženo"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Predloženi jezici"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Predložene regije"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Svi jezici"</string>
@@ -2052,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Želite li dopustiti aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> da pristupa svim zapisnicima uređaja?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Omogući jednokratni pristup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dopustiti"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"U zapisnicima uređaja bilježi se što se događa na uređaju. Aplikacije mogu koristiti te zapisnike kako bi pronašle i riješile poteškoće.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, pa pristup svim zapisnicima uređaja odobrite samo pouzdanim aplikacijama. \n\nAko ne dopustite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač vašeg uređaja i dalje može pristupati nekim zapisnicima ili podacima na vašem uređaju."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e71a92f..01b6f90 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Túl sok próbálkozás. Ujjlenyomat-érzékelő letiltva."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nincs kiválasztva"</string>
     <string name="selected" msgid="6614607926197755875">"kiválasztva"</string>
     <string name="not_selected" msgid="410652016565864475">"nincs kiválasztva"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} csillagból egy}other{{max} csillagból #}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"folyamatban"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Művelet végrehajtása a következővel:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Művelet elvégzése a(z) %1$s segítségével"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Régió beállítása"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Adja meg a nyelvet"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Javasolt"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Javasolt"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Javasolt nyelvek"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Javasolt régiók"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Minden nyelv"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Engedélyezi a(z) <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> számára, hogy hozzáférjen az összes eszköznaplóhoz?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Egyszeri hozzáférés engedélyezése"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tiltás"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Az eszköznaplók rögzítik, hogy mi történik az eszközén. Az alkalmazások ezeket a naplókat használhatják a problémák megkeresésére és kijavítására.\n\nBizonyos naplók bizalmas adatokat is tartalmazhatnak, ezért csak olyan alkalmazások számára engedélyezze az összes eszköznaplóhoz való hozzáférést, amelyekben megbízik. \n\nHa nem engedélyezi ennek az alkalmazásnak, hogy hozzáférjen az összes eszköznaplójához, az app továbbra is hozzáférhet a saját naplóihoz. Előfordulhat, hogy az eszköz gyártója továbbra is hozzáfér az eszközön található bizonyos naplókhoz és adatokhoz."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne jelenjen meg újra"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"A(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazás részleteket szeretne megjeleníteni a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Szerkesztés"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 9918859..86560be 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Չափից շատ փորձ եք կատարել: Մատնահետքերի սկաներն անջատվել է:"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"նշված չէ"</string>
     <string name="selected" msgid="6614607926197755875">"ընտրված է"</string>
     <string name="not_selected" msgid="410652016565864475">"ընտրված չէ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Մեկ աստղ՝ {max}-ից}one{# աստղ՝ {max}-ից}other{# աստղ՝ {max}-ից}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ընթացքում է"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ավարտել գործողությունը` օգտագործելով"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Եզրափակել գործողությունը՝ օգտագործելով %1$s"</string>
@@ -1422,7 +1422,7 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> հիշասարքն անջատվում է"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Չհեռացնեք սարքը"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"Կարգավորել"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"Անջատել"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"Հանել"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"Ուսումնասիրել"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Աուդիոելքի սարքի փոխարկում"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g>-ը տեղադրված չէ"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Նախընտրելի տարածաշրջան"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Մուտքագրեք լեզուն"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Առաջարկվող"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Առաջարկվող"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Առաջարկվող լեզուներ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Առաջարկվող տարածաշրջաններ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Բոլոր լեզուները"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Հասանելի դարձնե՞լ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> հավելվածին սարքի բոլոր մատյանները"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Թույլատրել մեկանգամյա մուտքը"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Չթույլատրել"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Այն, ինչ տեղի է ունենում ձեր սարքում, գրանցվում է սարքի մատյաններում։ Հավելվածները կարող են դրանք օգտագործել անսարքությունները հայտնաբերելու և վերացնելու նպատակով։\n\nՔանի որ որոշ մատյաններ անձնական տեղեկություններ են պարունակում, խորհուրդ ենք տալիս հասանելի դարձնել ձեր սարքի բոլոր մատյանները միայն այն հավելվածներին, որոնց վստահում եք։ \n\nԵթե այս հավելվածին նման թույլտվություն չեք տվել, դրան նախկինի պես հասանելի կլինեն իր մատյանները։ Հնարավոր է՝ ձեր սարքի արտադրողին ևս հասանելի լինեն սարքի որոշ մատյաններ և տեղեկություններ։"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Այլևս ցույց չտալ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> հավելվածն ուզում է ցուցադրել հատվածներ <xliff:g id="APP_2">%2$s</xliff:g> հավելվածից"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Փոփոխել"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Ստուգել ակտիվ հավելվածները"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Հնարավոր չէ օգտագործել հեռախոսի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Հնարավոր չէ օգտագործել պլանշետի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Այս բովանդակությունը հասանելի չէ հեռարձակման ընթացքում։ Օգտագործեք ձեր հեռախոսը։"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Կանխադրված"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ՔԱՐՏ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 0914da5..b145e20 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Terlalu sering dicoba. Sensor sidik jari dinonaktifkan."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"tidak dicentang"</string>
     <string name="selected" msgid="6614607926197755875">"dipilih"</string>
     <string name="not_selected" msgid="410652016565864475">"tidak dipilih"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Satu bintang dari {max}}other{# bintang dari {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"dalam proses"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferensi wilayah"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Ketik nama bahasa"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Disarankan"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Disarankan"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Bahasa yang disarankan"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Wilayah yang disarankan"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Semua bahasa"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Izinkan <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> mengakses semua log perangkat?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Izinkan akses satu kali"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan izinkan"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Log perangkat merekam hal-hal yang terjadi di perangkat Anda. Aplikasi dapat menggunakan log ini untuk menemukan dan memperbaiki masalah.\n\nBeberapa log mungkin berisi info sensitif, jadi hanya izinkan aplikasi yang Anda percayai untuk mengakses semua log perangkat. \n\nJika Anda tidak mengizinkan aplikasi ini mengakses semua log perangkat, aplikasi masih dapat mengakses log-nya sendiri. Produsen perangkat masih dapat mengakses beberapa log atau info di perangkat Anda."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tampilkan lagi"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ingin menampilkan potongan <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0e86fc1..6f48de2 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Of margar tilraunir. Fingrafaralesari gerður óvirkur."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ekki valið"</string>
     <string name="selected" msgid="6614607926197755875">"valið"</string>
     <string name="not_selected" msgid="410652016565864475">"ekki valið"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Ein stjarna af {max}}one{# stjarna af {max}}other{# stjörnur af {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"í gangi"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Ljúka aðgerð með"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Ljúka aðgerð með %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Svæðisval"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Sláðu inn heiti tungumáls"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Tillögur"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Tillögur"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Tillögur að tungumálum"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Tillögur að svæðum"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Öll tungumál"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Veita <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aðgang að öllum annálum í tækinu?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Leyfa aðgang í eitt skipti"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ekki leyfa"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Annálar tækisins skrá það sem gerist í tækinu. Forrit geta notað þessa annála til að finna og lagfæra vandamál.\n\nTilteknir annálar innihalda viðkvæmar upplýsingar og því skaltu einungis veita forritum sem þú treystir aðgang að öllum annálum tækisins. \n\nEf þú veitir þessu forriti ekki aðgang að öllum annálum tækisins hefur það áfram aðgang að eigin annálum. Framleiðandi tækisins getur þó hugsanlega opnað tiltekna annála eða upplýsingar í tækinu."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ekki sýna aftur"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill sýna sneiðar úr <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Breyta"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skoða virk forrit"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ekki er hægt að opna myndavél símans úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ekki er hægt að opna myndavél spjaldtölvunnar úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Ekki er hægt að opna þetta á meðan streymi stendur yfir. Prófaðu það í símanum í staðinn."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sjálfgildi kerfis"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0ade2dda..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Troppi tentativi. Sensore di impronte disattivato."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Regione preferita"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Digita nome lingua"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Suggerite"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Suggerite"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Lingue suggerite"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regioni consigliate"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Tutte le lingue"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Consentire all\'app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> di accedere a tutti i log del dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Consenti accesso una tantum"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non consentire"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"I log del dispositivo registrano tutto ciò che succede sul tuo dispositivo. Le app possono usare questi log per individuare problemi e correggerli.\n\nAlcuni log potrebbero contenere informazioni sensibili, quindi concedi l\'accesso a tutti i log del dispositivo soltanto alle app attendibili. \n\nSe le neghi l\'accesso a tutti i log del dispositivo, questa app può comunque accedere ai propri log. Il produttore del tuo dispositivo potrebbe essere comunque in grado di accedere ad alcuni log o informazioni sul dispositivo."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non mostrare più"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"L\'app <xliff:g id="APP_0">%1$s</xliff:g> vuole mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Modifica"</string>
@@ -2112,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>
@@ -2293,8 +2292,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verifica le app attive"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossibile accedere alla fotocamera del telefono dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossibile accedere alla fotocamera del tablet dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Impossibile accedere a questi contenuti durante lo streaming. Prova a usare il telefono."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predefinita di sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SCHEDA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7db42df..7a460a3 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"יותר מדי ניסיונות. חיישן טביעות האצבע הושבת."</string>
+    <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 +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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"לא מסומן"</string>
     <string name="selected" msgid="6614607926197755875">"נבחר"</string>
     <string name="not_selected" msgid="410652016565864475">"לא נבחר"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{כוכב אחד מתוך {max}}two{# כוכבים מתוך {max}}many{# כוכבים מתוך {max}}other{# כוכבים מתוך {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"בתהליך"</string>
     <string name="whichApplication" msgid="5432266899591255759">"השלמת הפעולה באמצעות"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏השלמת הפעולה באמצעות %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"העדפת אזור"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"יש להקליד את שם השפה"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"הצעות"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"הצעות"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"השפות המוצעות"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"האזורים המוצעים"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"כל השפות"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"לתת לאפליקציה <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> הרשאת גישה לכל יומני המכשיר?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"הרשאת גישה חד-פעמית"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"אין אישור"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ביומני המכשיר מתועדת הפעילות במכשיר. האפליקציות יכולות להשתמש ביומנים האלה כדי למצוא בעיות ולפתור אותן.\n\nהמידע בחלק מהיומנים יכול להיות רגיש, לכן יש לתת הרשאת גישה לכל יומני המכשיר רק לאפליקציות מהימנות. \n\nגם אם האפליקציה הזו לא תקבל הרשאת גישה לכל יומני המכשיר, היא תוכל לגשת ליומנים שלה. יכול להיות שליצרן המכשיר עדיין תהיה גישה לחלק מהיומנים או למידע במכשיר שלך."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"אין להציג שוב"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> רוצה להציג חלקים מ-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"עריכה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7ac5166..cf8521f8 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"試行回数が上限を超えました。指紋認証センサーを無効にしました。"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1167,7 @@
     <string name="not_checked" msgid="7972320087569023342">"OFF"</string>
     <string name="selected" msgid="6614607926197755875">"選択済み"</string>
     <string name="not_selected" msgid="410652016565864475">"未選択"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} つ星中 1 つ星の評価}other{{max} つ星中 # つ星の評価}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"進行中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"アプリケーションを選択"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sを使用してアクションを完了"</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>
@@ -1925,8 +1924,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"地域設定"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"言語名を入力"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"言語の候補"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"候補"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"言語の候補"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"地域の候補"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"すべての言語"</string>
@@ -2051,8 +2049,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> にすべてのデバイスログへのアクセスを許可しますか?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"1 回限りのアクセスを許可"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"許可しない"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合も、このアプリはアプリ独自のログにアクセスできます。また、デバイスのメーカーもデバイスの一部のログや情報にアクセスできる可能性があります。"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"次回から表示しない"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」が「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示をリクエストしています"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"編集"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 5bd6aa6..ae14cc9 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"დაფიქსირდა მეტისმეტად ბევრი მცდელობა. თითის ანაბეჭდის სენსორი გათიშულია."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"არ არის მონიშნული"</string>
     <string name="selected" msgid="6614607926197755875">"არჩეულია"</string>
     <string name="not_selected" msgid="410652016565864475">"არ არის არჩეული"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{ერთი ვარსკვლავი სულ {max}-დან}other{# ვარსკვლავი სულ {max}-დან}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"მიმდინარეობს"</string>
     <string name="whichApplication" msgid="5432266899591255759">"რა გამოვიყენოთ?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"მოქმედების %1$s-ის გამოყენებით დასრულება"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"რეგიონის პარამეტრები"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"აკრიფეთ ენის სახელი"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"რეკომენდებული"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"რეკომენდებული"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"შემოთავაზებული ენები"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"შეთავაზებული რეგიონები"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ყველა ენა"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"გსურთ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>-ს მიანიჭოთ მოწყობილობის ყველა ჟურნალზე წვდომა?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ერთჯერადი წვდომის დაშვება"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"არ დაიშვას"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა თქვენს ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"აღარ გამოჩნდეს"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>-ს სურს, გაჩვენოთ <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"რედაქტირება"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 7552ed8b..54edba3 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -605,7 +605,8 @@
     <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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Тым көп әрекет жасалды. Саусақ ізін оқу сканері өшірілді."</string>
+    <!-- no translation found for fingerprint_error_lockout_permanent (9060651300306264843) -->
+    <skip />
     <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>
@@ -634,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>
@@ -1167,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"белгіленбеген"</string>
     <string name="selected" msgid="6614607926197755875">"таңдалған"</string>
     <string name="not_selected" msgid="410652016565864475">"таңдалмаған"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1/{max} жұлдыз}other{#/{max} жұлдыз}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"орындалуда"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Әрекетті аяқтау"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Әрекетті %1$s қолданбасын пайдаланып аяқтау"</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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Аймақ параметрі"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Тіл атауын теріңіз"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Ұсынылған"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ұсынылатын аймақтар"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Ұсынылған тілдер"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Ұсынылған аймақтар"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Барлық тілдер"</string>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> қолданбасына барлық құрылғының журналын пайдалануға рұқсат берілсін бе?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Бір реттік пайдалану рұқсатын беру"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Рұқсат бермеу"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Журналдарға құрылғыда не болып жатқаны жазылады. Қолданбалар осы журналдарды қате тауып, түзету үшін пайдаланады.\n\nКейбір журналдарда құпия ақпарат болуы мүмкін. Сондықтан барлық құрылғының журналын пайдалану рұқсаты тек сенімді қолданбаларға берілуі керек. \n\nБұл қолданбаға барлық құрылғының журналын пайдалануға рұқсат бермесеңіз де, ол өзінің журналдарын пайдалана береді. Құрылғы өндірушісі де құрылғыдағы кейбір журналдарды немесе ақпаратты пайдалануы мүмкін."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Қайта көрсетілмесін"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> қолданбасы <xliff:g id="APP_2">%2$s</xliff:g> қолданбасының үзінділерін көрсеткісі келеді"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Өзгерту"</string>
@@ -2293,8 +2292,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Белсенді қолданбаларды тексеру"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан телефон камерасын пайдалану мүмкін емес."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан планшет камерасын пайдалану мүмкін емес."</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Трансляция кезінде мазмұнды көру мүмкін емес. Оның орнына телефоннан көріңіз."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Жүйенің әдепкі параметрі"</string>
     <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g>-КАРТА"</string>
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index c941e0a..0d3d07d 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ព្យាយាមចូលច្រើនដងពេកហើយ។ ឧបករណ៍ចាប់ស្នាមម្រាមដៃត្រូវ​បានបិទ។"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"មិន​បាន​ធីក​"</string>
     <string name="selected" msgid="6614607926197755875">"បាន​ជ្រើសរើស"</string>
     <string name="not_selected" msgid="410652016565864475">"មិនបានជ្រើសរើសទេ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{ផ្កាយមួយ​ក្នុងចំណោមផ្កាយ {max}}other{ផ្កាយ # ក្នុងចំណោមផ្កាយ {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"កំពុងដំណើរការ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ​ %1$s"</string>
@@ -1425,7 +1425,7 @@
     <string name="ext_media_unmount_action" msgid="966992232088442745">"ដកចេញ"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"រុករក"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"លទ្ធផល Switch"</string>
-    <string name="ext_media_missing_title" msgid="3209472091220515046">"បាត់ <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_missing_title" msgid="3209472091220515046">"បាត់<xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"បញ្ចូល​ឧបករណ៍​ម្តងទៀត"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"កំពុងផ្លាស់ទី <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"កំពុងផ្លាស់ទីទិន្នន័យ…"</string>
@@ -1565,7 +1565,7 @@
     <string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
     <string name="storage_internal" msgid="8490227947584914460">"ទំហំផ្ទុករួមខាងក្នុង"</string>
-    <string name="storage_sd_card" msgid="3404740277075331881">"កាត​អេសឌី"</string>
+    <string name="storage_sd_card" msgid="3404740277075331881">"កាត SD"</string>
     <string name="storage_sd_card_label" msgid="7526153141147470509">"កាត SD <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="448030813201444573">"ឧបករណ៍ផ្ទុក USB"</string>
     <string name="storage_usb_drive_label" msgid="6631740655876540521">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ចំណូលចិត្តតំបន់"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"វាយបញ្ចូលឈ្មោះភាសា"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"បាន​ណែនាំ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"បាន​ណែនាំ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"ភាសា​ដែល​បាន​ណែ​នាំ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"តំបន់​ដែល​បាន​ណែនាំ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ភាសាទាំងអស់"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"អនុញ្ញាតឱ្យ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ឬ?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"អនុញ្ញាតឱ្យចូលប្រើ​ម្ដង"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"មិនអនុញ្ញាត"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"កំណត់ហេតុឧបករណ៍កត់ត្រាអ្វីដែលកើតឡើងនៅលើឧបករណ៍របស់អ្នក។ កម្មវិធីអាចប្រើកំណត់ហេតុទាំងនេះដើម្បីស្វែងរក និងដោះស្រាយបញ្ហាបាន។\n\nកំណត់ហេតុមួយចំនួនអាចមានព័ត៌មានរសើប ដូច្នេះគួរអនុញ្ញាតឱ្យចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់សម្រាប់តែកម្មវិធីដែលអ្នកទុកចិត្តប៉ុណ្ណោះ។ \n\nប្រសិនបើអ្នកមិនអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ទេ វានៅតែអាចចូលប្រើកំណត់ហេតុរបស់វាផ្ទាល់បាន។ ក្រុមហ៊ុន​ផលិត​ឧបករណ៍របស់អ្នក​ប្រហែលជា​នៅតែអាចចូលប្រើ​កំណត់ហេតុ ឬព័ត៌មានមួយចំនួន​នៅលើឧបករណ៍​របស់អ្នក​បានដដែល។"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"កុំ​បង្ហាញ​ម្ដង​ទៀត"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ចង់​បង្ហាញ​ស្ថិតិ​ប្រើប្រាស់​របស់ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"កែ"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ពិនិត្យមើលកម្មវិធីសកម្ម"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"មិនអាច​ចូលប្រើ​កាមេរ៉ាទូរសព្ទ​ពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​បានទេ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"មិនអាច​ចូលប្រើ​កាមេរ៉ា​ថេប្លេតពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​បានទេ"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"មិន​អាច​ចូល​ប្រើប្រាស់​ខ្លឹមសារ​នេះ​បាន​ទេ ពេល​ផ្សាយ។ សូមសាកល្បងប្រើ​នៅលើ​ទូរសព្ទរបស់អ្នក​ជំនួសវិញ។"</string>
     <string name="system_locale_title" msgid="711882686834677268">"លំនាំ​ដើម​ប្រព័ន្ធ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"កាត <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 31ec216..9925a26 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ಹಲವು ಬಾರಿ ಪ್ರಯತ್ನಿಸಿದ್ದೀರಿ. ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ನಿಷ್ಕ್ರಿಯಗೊಂಡಿದೆ."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="selected" msgid="6614607926197755875">"ಆಯ್ಕೆಮಾಡಲಾಗಿದೆ"</string>
     <string name="not_selected" msgid="410652016565864475">"ಆಯ್ಕೆಮಾಡಲಾಗಿಲ್ಲ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} ರಲ್ಲಿ ಒಂದು ನಕ್ಷತ್ರ}one{{max} ರಲ್ಲಿ # ನಕ್ಷತ್ರಗಳು}other{{max} ರಲ್ಲಿ # ನಕ್ಷತ್ರಗಳು}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ಪ್ರದೇಶ ಪ್ರಾಶಸ್ತ್ಯ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ಭಾಷೆ ಹೆಸರನ್ನು ಟೈಪ್ ಮಾಡಿ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"ಸೂಚಿತ ಭಾಷೆ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ಸೂಚಿಸಲಾಗಿರುವುದು"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"ಸೂಚಿಸಲಾದ ಭಾಷೆಗಳು"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"ಸೂಚಿಸಲಾದ ಪ್ರದೇಶಗಳು"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"ಎಲ್ಲಾ ಸಾಧನದ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ಗೆ ಅನುಮತಿಸುವುದೇ?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ಒಂದು ಬಾರಿಯ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ಅನುಮತಿಸಬೇಡಿ"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್‌ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು ಈ ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಈಗಲೂ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್‌ಗಳನ್ನು <xliff:g id="APP_0">%1$s</xliff:g> ತೋರಿಸಲು ಬಯಸಿದೆ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ಎಡಿಟ್"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index c17ab787..40c545f 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"시도 횟수가 너무 많습니다. 지문 센서가 사용 중지되었습니다."</string>
+    <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>
@@ -634,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>
@@ -647,9 +648,9 @@
     <string name="face_acquired_recalibrate" msgid="8724013080976469746">"얼굴을 다시 등록해 주세요."</string>
     <string name="face_acquired_too_different" msgid="2520389515612972889">"얼굴을 인식할 수 없습니다. 다시 시도해 주세요."</string>
     <string name="face_acquired_too_similar" msgid="8882920552674125694">"얼굴의 위치를 조금 변경해 주세요."</string>
-    <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
-    <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"휴대전화를 좀 더 똑바로 바라봐 주세요."</string>
+    <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"휴대전화를 좀 더\\n똑바로 바라봐 주세요."</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"휴대전화를 좀 더\\n똑바로 바라봐 주세요."</string>
+    <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"휴대전화를 좀 더\\n똑바로 바라봐 주세요."</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"얼굴이 가려지지 않도록 해 주세요."</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"검은색 바를 포함한 화면 상단을 청소하세요."</string>
     <!-- no translation found for face_acquired_dark_glasses_detected (5643703296620631986) -->
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"선택 안함"</string>
     <string name="selected" msgid="6614607926197755875">"선택됨"</string>
     <string name="not_selected" msgid="410652016565864475">"선택되지 않음"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{별 {max}개 중 1개}other{별 {max}개 중 #개}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"진행 중"</string>
     <string name="whichApplication" msgid="5432266899591255759">"작업을 수행할 때 사용하는 애플리케이션"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s을(를) 사용하여 작업 완료"</string>
@@ -1422,7 +1422,7 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> 마운트 해제 중"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"외부 미디어를 제거하지 마세요."</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"설정"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"마운트 해제"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"꺼내기"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"둘러보기"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"출력 전환"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> 없음"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"지역 환경설정"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"언어 이름 입력"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"추천"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"추천 지역"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"추천 언어"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"추천 지역"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"모든 언어"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>에서 모든 기기 로그에 액세스하도록 허용하시겠습니까?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"일회성 액세스 허용"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"허용 안함"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"기기 로그에 기기에서 발생한 상황이 기록됩니다. 앱은 문제를 찾고 해결하는 데 이 로그를 사용할 수 있습니다.\n\n일부 로그는 민감한 정보를 포함할 수 있으므로 신뢰할 수 있는 앱만 모든 기기 로그에 액세스하도록 허용하세요. \n\n앱에 전체 기기 로그에 대한 액세스 권한을 부여하지 않아도 앱이 자체 로그에는 액세스할 수 있습니다. 기기 제조업체에서 일부 로그 또는 기기 내 정보에 액세스할 수도 있습니다."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"다시 표시 안함"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>에서 <xliff:g id="APP_2">%2$s</xliff:g>의 슬라이스를 표시하려고 합니다"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"수정"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"활성 상태의 앱 확인"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 휴대전화 카메라에 액세스할 수 없습니다."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 태블릿 카메라에 액세스할 수 없습니다."</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"스트리밍 중에는 액세스할 수 없습니다. 대신 휴대전화에서 시도해 보세요."</string>
     <string name="system_locale_title" msgid="711882686834677268">"시스템 기본값"</string>
     <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> 카드"</string>
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 499b8b4..f27b0d6 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Өтө көп жолу аракет жасадыңыз. Манжа изинин сенсору өчүрүлдү."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"белгилене элек"</string>
     <string name="selected" msgid="6614607926197755875">"тандалган"</string>
     <string name="not_selected" msgid="410652016565864475">"тандалган жок"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} ичинен бир жылдыз}other{{max} ичинен # жылдыз}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"аткарылууда"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Кайсынысын колдоносуз?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s аркылуу аракетти аягына чейин чыгаруу"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Чөлкөмдүк жөндөөлөр"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Тилди киргизиңиз"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Сунушталгандар"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Сунушталган"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Сунушталган тилдер"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Сунушталган региондор"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Бардык тилдер"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> колдонмосуна түзмөктөгү бардык таржымалдарды жеткиликтүү кыласызбы?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Бир жолу жеткиликтүү кылуу"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Жок"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Түзмөктө аткарылган бардык аракеттер түзмөктүн таржымалдарында сакталып калат. Колдонмолор бул таржымалдарды колдонуп, маселелерди оңдошот.\n\nАйрым таржымалдарда купуя маалымат болушу мүмкүн, андыктан түзмөктөгү бардык таржымалдарды ишенимдүү колдонмолорго гана пайдаланууга уруксат бериңиз. \n\nЭгер бул колдонмого түзмөктөгү айрым таржымалдарга кирүүгө тыюу салсаңыз, ал өзүнүн таржымалдарын пайдалана берет. Түзмөктү өндүрүүчү түзмөгүңүздөгү айрым таржымалдарды же маалыматты көрө берет."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Экинчи көрүнбөсүн"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> колдонмосу <xliff:g id="APP_2">%2$s</xliff:g> үлгүлөрүн көрсөткөнү жатат"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Түзөтүү"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index bdbe79e..7c9f815 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ພະຍາຍາມຫຼາຍເທື່ອເກີນໄປ. ລະບົບປິດການເຮັດວຽກຂອງເຊັນເຊີລາຍນິ້ວມືແລ້ວ."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ບໍ່ໄດ້ໝາຍຖືກ"</string>
     <string name="selected" msgid="6614607926197755875">"ເລືອກແລ້ວ"</string>
     <string name="not_selected" msgid="410652016565864475">"ບໍ່ໄດ້ເລືອກແລ້ວ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{ໜຶ່ງດາວຈາກເຕັມ {max} ດາວ}other{# ດາວຈາກເຕັມ {max} ດາວ}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ກຳລັງດຳເນີນການ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ດຳເນີນການໂດຍໃຊ້"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"ສຳ​ເລັດ​​​ການ​ດຳ​ເນີນ​ການ​ໂດຍ​ໃຊ້ %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ການຕັ້ງຄ່າພາກພື້ນ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ພິມຊື່ພາສາ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"ແນະນຳ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ແນະນຳ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"ພາສາທີ່ແນະນຳ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"ພາກ​ພື້ນ​ທີ່ແນະ​ນໍາ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ທຸກພາ​ສາ​"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"ອະນຸຍາດໃຫ້ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດບໍ?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ອະນຸຍາດການເຂົ້າເຖິງແບບເທື່ອດຽວ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ບໍ່ອະນຸຍາດ"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ແກ້ໄຂ"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ກວດສອບແອັບທີ່ເຄື່ອນໄຫວ"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງໂທລະສັບຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງແທັບເລັດຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"ບໍ່ສາມາດເຂົ້າເຖິງເນື້ອຫານີ້ໄດ້ໃນຂະນະທີ່ຍັງສະຕຣີມຢູ່. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
     <string name="system_locale_title" msgid="711882686834677268">"ຄ່າເລີ່ມຕົ້ນຂອງລະບົບ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ບັດ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index fdb86fc8..2954f9c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Per daug bandymų. Piršto antspaudo jutiklis išjungtas."</string>
+    <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>
@@ -636,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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nepažymėta"</string>
     <string name="selected" msgid="6614607926197755875">"pasirinkta"</string>
     <string name="not_selected" msgid="410652016565864475">"nepasirinkta"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Viena žvaigždutė iš {max}}one{# žvaigždutė iš {max}}few{# žvaigždutės iš {max}}many{# žvaigždutės iš {max}}other{# žvaigždučių iš {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"vykdoma"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Užbaigti veiksmą naudojant"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Užbaigti veiksmą naudojant %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Regiono nuostata"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Įveskite kalbos pav."</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Siūloma"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Siūloma"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Siūlomos kalbos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Siūlomi regionai"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Visos kalbos"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Leisti „<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>“ pasiekti visus įrenginio žurnalus?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Leisti vienkartinę prieigą"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neleisti"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Įrenginyje įrašoma, kas įvyksta jūsų įrenginyje. Programos gali naudoti šiuos žurnalus, kad surastų ir išspręstų problemas.\n\nKai kuriuose žurnaluose gali būti neskelbtinos informacijos, todėl visus įrenginio žurnalus leiskite pasiekti tik programoms, kuriomis pasitikite. \n\nJei neleisite šiai programai pasiekti visų įrenginio žurnalų, ji vis tiek galės pasiekti savo žurnalus. Įrenginio gamintojui vis tiek gali būti leidžiama pasiekti tam tikrus žurnalus ar informaciją jūsų įrenginyje."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daugiau neberodyti"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"„<xliff:g id="APP_0">%1$s</xliff:g>“ nori rodyti „<xliff:g id="APP_2">%2$s</xliff:g>“ fragmentus"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Redaguoti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 7b8fae9..853a490 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -606,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Pārāk daudz mēģinājumu. Pirksta nospieduma sensors atspējots."</string>
+    <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>
@@ -635,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>
@@ -1168,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nav atzīmēts"</string>
     <string name="selected" msgid="6614607926197755875">"atlasīts"</string>
     <string name="not_selected" msgid="410652016565864475">"nav atlasīts"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Viena zvaigznīte no {max}}zero{# zvaigznīšu no {max}}one{# zvaigznīte no {max}}other{# zvaigznītes no {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"notiek apstrāde"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Izvēlieties lietotni"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Pabeigt darbību, izmantojot %1$s"</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>
@@ -1926,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Reģiona preference"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Ierakstiet valodas nosaukumu"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Ieteiktās"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ieteiktie"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Ieteiktās valodas"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Ieteiktie reģioni"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Visas valodas"</string>
@@ -2052,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Vai atļaujat lietotnei <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> piekļūt visiem ierīces žurnāliem?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Atļaut vienreizēju piekļuvi"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Neatļaut"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Ierīces žurnālos tiek reģistrēti ierīces procesi un notikumi. Lietotņu izstrādātāji var izmantot šos žurnālus, lai atrastu un izlabotu problēmas savās lietotnēs.\n\nDažos žurnālos var būt ietverta sensitīva informācija, tāpēc atļaujiet tikai uzticamām lietotnēm piekļūt visiem ierīces žurnāliem. \n\nJa neatļausiet šai lietotnei piekļūt visiem ierīces žurnāliem, lietotnes izstrādātājs joprojām varēs piekļūt pašas lietotnes žurnāliem. Iespējams, ierīces ražotājs joprojām varēs piekļūt noteiktiem žurnāliem vai informācijai jūsu ierīcē."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vairs nerādīt"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Lietotne <xliff:g id="APP_0">%1$s</xliff:g> vēlas rādīt lietotnes <xliff:g id="APP_2">%2$s</xliff:g> sadaļas"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Rediģēt"</string>
@@ -2294,8 +2292,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Pārbaudiet aktīvās lietotnes"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nevar piekļūt tālruņa kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nevar piekļūt planšetdatora kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Straumēšanas laikā nevar piekļūt šim saturam. Mēģiniet tam piekļūt savā tālrunī."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistēmas noklusējums"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index e49d500..9ce43d1 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Премногу обиди. Сензорот за отпечатоци е оневозможен."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не е штиклирано"</string>
     <string name="selected" msgid="6614607926197755875">"избрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не е избрано"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Една ѕвезда од {max}}one{# ѕвезда од {max}}other{# ѕвезди од {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"во тек"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Активирај со"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Остварете го дејството со %1$s"</string>
@@ -1565,8 +1565,8 @@
     <string name="action_bar_home_description_format" msgid="5087107531331621803">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
     <string name="storage_internal" msgid="8490227947584914460">"Внатрешен споделен капацитет"</string>
-    <string name="storage_sd_card" msgid="3404740277075331881">"СД картичка"</string>
-    <string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> СД-картичка"</string>
+    <string name="storage_sd_card" msgid="3404740277075331881">"SD-картичка"</string>
+    <string name="storage_sd_card_label" msgid="7526153141147470509">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD-картичка"</string>
     <string name="storage_usb_drive" msgid="448030813201444573">"USB-меморија"</string>
     <string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-меморија"</string>
     <string name="storage_usb" msgid="2391213347883616886">"USB меморија"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Претпочитувања за регион"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Внесете име на јазик"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Предложени"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Предложени"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Предложени јазици"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Предложени региони"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Сите јазици"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Да се дозволи <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> да пристапува до целата евиденција на уредот?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дозволи еднократен пристап"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволувај"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не прикажувај повторно"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> сака да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверете ги активните апликации"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се пристапи до камерата на вашиот телефон од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се пристапи до камерата на вашиот таблет од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"До ова не може да се пристапи при стриминг. Наместо тоа, пробајте на вашиот телефон."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Стандардно за системот"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТИЧКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d03f04e..c71047d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"നിരവധി തവണ ശ്രമിച്ചതിനാൽ, ഫിംഗർപ്രിന്റ് സെൻസർ പ്രവർത്തനരഹിതമായി."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"പരിശോധിക്കാത്തത്"</string>
     <string name="selected" msgid="6614607926197755875">"തിരഞ്ഞെടുത്തു"</string>
     <string name="not_selected" msgid="410652016565864475">"തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}-ൽ ഒരു നക്ഷത്ര ചിഹ്നം}other{{max}-ൽ # നക്ഷത്ര ചിഹ്നം}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"പുരോഗതിയിലാണ്"</string>
     <string name="whichApplication" msgid="5432266899591255759">"പൂർണ്ണമായ പ്രവർത്തനം ഉപയോഗിക്കുന്നു"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ഉപയോഗിച്ച് പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
@@ -1422,7 +1422,7 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> ഒഴിവാക്കുന്നു"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"നീക്കം ചെയ്യരുത്"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"സജ്ജമാക്കുക"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"നിരസിക്കുക"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"ഒഴിവാക്കുക"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"അടുത്തറിയുക"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"ഔട്ട്പുട്ട് മാറുക"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> കാണുന്നില്ല"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"മേഖലാ മുൻഗണന"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ഭാഷ ടൈപ്പ് ചെയ്യുക"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"നിര്‍‌ദ്ദേശിച്ചത്"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"നിർദ്ദേശിച്ചവ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"നിർദ്ദേശിച്ച ഭാഷകൾ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"നിർദ്ദേശിച്ച പ്രദേശങ്ങൾ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"എല്ലാ ഭാഷകളും"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"എല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാൻ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> എന്നതിനെ അനുവദിക്കണോ?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ഒറ്റത്തവണ ആക്‌സസ് അനുവദിക്കുക"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"അനുവദിക്കരുത്"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്‌സസ് ചെയ്യാനായേക്കും."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"വീണ്ടും കാണിക്കരുത്"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"എഡിറ്റ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 1f4eaf9..417500d 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Хэт олон удаа оролдсон тул хурууны хээ мэдрэгчийг идэвхгүй болголоо."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"тэмдэглээгүй"</string>
     <string name="selected" msgid="6614607926197755875">"сонгосон"</string>
     <string name="not_selected" msgid="410652016565864475">"сонгоогүй"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}-с нэг од}other{{max}-с # од}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"үргэлжилж байна"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Үйлдлийг дуусгах"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ашиглан үйлдлийг гүйцээх"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Бүс нутгийн тохиргоо"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Улсын хэлийг бичнэ үү"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Санал болгосон"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Санал болгосон"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Санал болгосон хэл"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Санал болгосон бүс нутгууд"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Бүх хэл"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>-д төхөөрөмжийн бүх логт хандахыг зөвшөөрөх үү?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Нэг удаагийн хандалтыг зөвшөөрнө үү"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Бүү зөвшөөр"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Tаны төхөөрөмж үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Дахиж бүү харуул"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг (slices) харуулах хүсэлтэй байна"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Засах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a09a529..f91a18f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"खूप प्रयत्न करून झाले. फिंगरप्रिंट सेन्सर बंद आहे."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"तपासले नाही"</string>
     <string name="selected" msgid="6614607926197755875">"निवडला"</string>
     <string name="not_selected" msgid="410652016565864475">"निवडला नाही"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} पैकी एक तारा}other{{max} पैकी # तारे}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"प्रगतीपथावर आहे"</string>
     <string name="whichApplication" msgid="5432266899591255759">"याचा वापर करून क्रिया पूर्ण करा"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s वापरून क्रिया पूर्ण करा"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"प्रदेश प्राधान्य"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"भाषा नाव टाइप करा"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"सुचवलेल्या भाषा"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"सुचवलेले"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"सुचवलेल्या भाषा"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"सुचवलेले प्रदेश"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"सर्व भाषा"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्यायची आहे का?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक वेळ अ‍ॅक्सेसची अनुमती द्या"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमती देऊ नका"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"पुन्हा दाखवू नका"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवायचे आहेत"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"संपादित करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 6e9f493..9b76a16 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Terlalu banyak percubaan. Penderia cap jari dilumpuhkan."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"tidak ditandai"</string>
     <string name="selected" msgid="6614607926197755875">"dipilih"</string>
     <string name="not_selected" msgid="410652016565864475">"tidak dipilih"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Satu daripada {max} bintang}other{# daripada {max} bintang}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"dalam proses"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$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">"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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Pilihan wilayah"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Taipkan nama bahasa"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Dicadangkan"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Dicadangkan"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Bahasa yang dicadangkan"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Rantau yang disyorkan"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Semua bahasa"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Benarkan <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> mengakses semua log peranti?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Benarkan akses satu kali"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan benarkan"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Log peranti merekodkan perkara yang berlaku pada peranti anda. Apl dapat menggunakan log ini untuk menemukan dan membetulkan isu.\n\nSesetengah log mungkin mengandungi maklumat sensitif, jadi benarkan apl yang anda percaya sahaja untuk mengakses semua log peranti. \n\nJika anda tidak membenarkan apl ini mengakses semua log peranti, apl masih boleh mengakses log sendiri. Pengilang peranti anda mungkin masih dapat mengakses sesetengah log atau maklumat pada peranti anda."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tunjuk lagi"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> mahu menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Semak apl aktif"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera telefon daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Kandungan ini tidak boleh diakses semasa penstriman. Cuba pada telefon anda."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Lalai sistem"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KAD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index c038ed7..87916c4 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"အကြိမ်အရေအတွက် အလွန်များနေပါပြီ။ လက်ဗွေအာရုံခံကိရိယာ ပိတ်ထားပါသည်။"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ခြစ် မထား"</string>
     <string name="selected" msgid="6614607926197755875">"ရွေးချယ်ထားသည်"</string>
     <string name="not_selected" msgid="410652016565864475">"ရွေးချယ်မထားပါ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} ပွင့်အနက် ကြယ်တစ်ပွင့်}other{{max} ပွင့်အနက် ကြယ် # ပွင့်}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ဆောင်ရွက်နေသည်"</string>
     <string name="whichApplication" msgid="5432266899591255759">"အောက်ပါတို့ကို အသုံးပြုမှု အပြီးသတ်ခြင်း"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ကို သုံးပြီး လုပ်ဆောင်ချက် ပြီးဆုံးပါစေ"</string>
@@ -1422,11 +1422,11 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"<xliff:g id="NAME">%s</xliff:g> ကို ထုတ်နေသည်"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"မဖယ်ရှားပါနှင့်"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"သတ်မှတ်ရန်"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"ထုတ်မည်"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"ထုတ်ရန်"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"စူးစမ်းရန်"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"မီဒီယာအထွက် ပြောင်းရန်"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> ပျောက်နေသည်"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"စက်ပစ္စည်းကို ထပ်မံထည့်သွင်းပါ"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"ကတ်ကို ထပ်မံထည့်သွင်းပါ"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ရွှေ့နေစဉ်"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"ဒေတာများ ရွှေ့နေစဉ်"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"အကြောင်းအရာ လွှဲပြောင်းပြီးပါပြီ"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ဒေသရွေးချယ်မှု"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ဘာသာစကားအမည် ထည့်ပါ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"အကြံပြုထားသည်"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"အကြံပြုထားသည်"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"အကြံပြုထားသည့် ဘာသာစကားများ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"အကြံပြုထားသည့် ဒေသများ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ဘာသာစကားအားလုံး"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်ပြုမလား။"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"တစ်ခါသုံး ဝင်ခွင့်ပေးရန်"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ခွင့်မပြုပါ"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"သင့်စက်ရှိ အဖြစ်အပျက်များကို စက်မှတ်တမ်းများက မှတ်တမ်းတင်သည်။ အက်ပ်များက ပြဿနာများ ရှာဖွေပြီးဖြေရှင်းရန် ဤမှတ်တမ်းများကို သုံးနိုင်သည်။\n\nအချို့မှတ်တမ်းများတွင် သတိထားရမည့်အချက်အလက်များ ပါဝင်နိုင်သဖြင့် စက်မှတ်တမ်းအားလုံးကို ယုံကြည်ရသည့် အက်ပ်များကိုသာ သုံးခွင့်ပြုပါ။ \n\nဤအက်ပ်ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်မပြုသော်လည်း ၎င်းက ၎င်း၏ကိုယ်ပိုင်မှတ်တမ်းကို သုံးနိုင်ဆဲဖြစ်သည်။ သင့်စက်ရှိ အချို့မှတ်တမ်းများ (သို့) အချက်အလက်များကို သင့်စက်ထုတ်လုပ်သူက သုံးနိုင်ပါသေးသည်။"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"နောက်ထပ်မပြပါနှင့်"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> သည် <xliff:g id="APP_2">%2$s</xliff:g> ၏အချပ်များကို ပြသလိုသည်"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"တည်းဖြတ်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0aa7cdb..e101548 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"For mange forsøk. Fingeravtrykkssensoren er slått av."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ikke avmerket"</string>
     <string name="selected" msgid="6614607926197755875">"valgt"</string>
     <string name="not_selected" msgid="410652016565864475">"ikke valgt"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 stjerne av {max}}other{# stjerner av {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"pågår"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Fullfør med"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Fullfør handlingen med %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Regionsinnstilling"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Skriv inn språknavn"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Foreslått"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Foreslått"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Foreslåtte språk"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Foreslåtte regioner"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Alle språk"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Vil du gi <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> tilgang til alle enhetslogger?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Gi éngangstilgang"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ikke tillat"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Enhetslogger registrerer det som skjer på enheten din. Apper kan bruke disse loggene til å finne og løse problemer.\n\nNoen logger kan inneholde sensitiv informasjon, så du bør bare gi tilgang til alle enhetslogger til apper du stoler på. \n\nHvis du ikke gir denne appen tilgang til alle enhetslogger, har den fortsatt tilgang til sine egne logger. Enhetsprodusenten kan fortsatt ha tilgang til visse logger eller noe informasjon på enheten din."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ikke vis igjen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vil vise <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Endre"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 3f653d9..b2bf381 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"अत्यन्त धेरै प्रयासहरू। फिंगरप्रिन्ट सेन्सरलाई असक्षम पारियो।"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"जाँच गरिएको छैन"</string>
     <string name="selected" msgid="6614607926197755875">"चयन गरियो"</string>
     <string name="not_selected" msgid="410652016565864475">"चयन गरिएन"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} मा एक तारा}other{{max} मा # तारा}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"जारी छ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"निम्न एपको प्रयोग गरी कारबाही पुरा गर्नुहोस्: %1$s"</string>
@@ -1426,7 +1426,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"अन्वेषण गर्नुहोस्"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"आउटपुट बदल्नुहोस्"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> हराइरहेको"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"यन्त्र फेरि घुसाउनुहोस्"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"डिभाइस फेरि हाल्नुहोस्"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> सार्दै"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"डेटा सार्दै..."</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"सामग्री स्थानान्तरण गरियो"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"क्षेत्रको प्राथमिकता"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"भाषाको नाम टाइप गर्नुहोस्"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"सिफारिस गरिएको"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"सिफारिस गरिएको"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"सिफारिस गरिएका भाषाहरू"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"सिफारिस गरिएका क्षेत्रहरू"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"सम्पूर्ण भाषाहरू"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> लाई डिभाइसका सबै लग हेर्ने अनुमति दिने हो?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक पटक प्रयोग गर्ने अनुमति दिनुहोस्"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमति नदिनुहोस्"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"डिभाइसका लगले तपाईंको डिभाइसमा भएका विभिन्न गतिविधिको अभिलेख राख्छ। एपहरू यी लगका आधारमा समस्या पत्ता लगाउन र तिनको समाधान गर्न सक्छन्।\n\nकेही लगहरूमा संवेदनशील जानकारी समावेश हुन सक्ने भएकाले आफूले भरोसा गर्ने एपलाई मात्र डिभाइसका सबै लग हेर्ने अनुमति दिनुहोस्। \n\nतपाईंले यो एपलाई डिभाइसका सबै लग हेर्ने अनुमति दिनुभएन भने पनि यसले आफ्नै लग भने हेर्न सक्छ। तपाईंको डिभाइसको उत्पादकले पनि तपाईंको डिभाइसमा भएका केही लग वा जानकारी हेर्न सक्ने सम्भावना हुन्छ।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"फेरि नदेखाइयोस्"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ले <xliff:g id="APP_2">%2$s</xliff:g> का स्लाइसहरू देखाउन चाहन्छ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"सम्पादन गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bcf0c3c..9811e27 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Te veel pogingen. Vingerafdruksensor staat uit."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"niet aangevinkt"</string>
     <string name="selected" msgid="6614607926197755875">"geselecteerd"</string>
     <string name="not_selected" msgid="410652016565864475">"niet geselecteerd"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Eén ster van {max}}other{# sterren van {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"bezig"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Actie voltooien met"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Actie voltooien via %1$s"</string>
@@ -1426,7 +1426,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"Verkennen"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Uitvoer wijzigen"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> ontbreekt"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"Voer apparaat opnieuw in"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"Voer het apparaat opnieuw in"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> verplaatsen"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Gegevens verplaatsen"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"Contentoverdracht is voltooid"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Regiovoorkeur"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Typ de naam van een taal"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Voorgesteld"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Voorgesteld"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Voorgestelde talen"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Voorgestelde regio\'s"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Alle talen"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> toegang geven tot alle apparaatlogboeken?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Eenmalige toegang toestaan"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Niet toestaan"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Apparaatlogboeken leggen vast wat er op je apparaat gebeurt. Apps kunnen deze logboeken gebruiken om problemen op te sporen en te verhelpen.\n\nSommige logboeken kunnen gevoelige informatie bevatten, dus geef alleen apps die je vertrouwt toegang tot alle apparaatlogboeken. \n\nAls je deze app geen toegang tot alle apparaatlogboeken geeft, heeft de app nog wel toegang tot de eigen logboeken. De fabrikant van je apparaat heeft misschien nog steeds toegang tot bepaalde logboeken of informatie op je apparaat."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Niet opnieuw tonen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> tonen"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Bewerken"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index a77ea2f..d3cbaec 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -211,7 +211,7 @@
     <string name="silent_mode" msgid="8796112363642579333">"ସାଇଲେଣ୍ଟ ମୋଡ୍"</string>
     <string name="turn_on_radio" msgid="2961717788170634233">"ୱେୟାରଲେସ୍‌କୁ ଚାଲୁ କରନ୍ତୁ"</string>
     <string name="turn_off_radio" msgid="7222573978109933360">"ୱେୟାରଲେସ୍‌କୁ ବନ୍ଦ କରନ୍ତୁ"</string>
-    <string name="screen_lock" msgid="2072642720826409809">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌"</string>
+    <string name="screen_lock" msgid="2072642720826409809">"ସ୍କ୍ରିନ ଲକ"</string>
     <string name="power_off" msgid="4111692782492232778">"ପାୱାର ବନ୍ଦ ଅଛି"</string>
     <string name="silent_mode_silent" msgid="5079789070221150912">"ରିଙ୍ଗର୍‍ ଅଫ୍‍ ଅଛି"</string>
     <string name="silent_mode_vibrate" msgid="8821830448369552678">"ରିଙ୍ଗର୍‍ କମ୍ପନ"</string>
@@ -235,7 +235,7 @@
     <string name="global_actions" product="tablet" msgid="4412132498517933867">"ଟାବଲେଟ ବିକଳ୍ପ"</string>
     <string name="global_actions" product="tv" msgid="3871763739487450369">"Android TVର ବିକଳ୍ପଗୁଡ଼ିକ"</string>
     <string name="global_actions" product="default" msgid="6410072189971495460">"ଫୋନ ବିକଳ୍ପ"</string>
-    <string name="global_action_lock" msgid="6949357274257655383">"ସ୍କ୍ରୀନ୍‌ ଲକ୍‌"</string>
+    <string name="global_action_lock" msgid="6949357274257655383">"ସ୍କ୍ରିନ ଲକ"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"ପାୱାର ବନ୍ଦ ଅଛି"</string>
     <string name="global_action_power_options" msgid="1185286119330160073">"ପାୱାର"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ବହୁଥର ପ୍ରୟାସ କରିଛନ୍ତି। ଟିପଚିହ୍ନ ସେନ୍ସର୍‍ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string>
     <string name="selected" msgid="6614607926197755875">"ଚୟନ କରାଯାଇଛି"</string>
     <string name="not_selected" msgid="410652016565864475">"ଚୟନ କରାଯାଇନାହିଁ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}ଟିରୁ ଗୋଟିଏ ଷ୍ଟାର}other{{max}ଟିରୁ #ଟି ଷ୍ଟାର}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ଚାଲୁଅଛି"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$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">"ଫୋନ"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ପସନ୍ଦର ଅଞ୍ଚଳ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ଭାଷାର ନାମ ଟାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"ପ୍ରସ୍ତାବିତ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ପ୍ରସ୍ତାବିତ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"ପ୍ରସ୍ତାବିତ ଭାଷାଗୁଡ଼ିକ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"ପ୍ରସ୍ତାବିତ ଅଞ୍ଚଳଗୁଡ଼ିକ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ସମସ୍ତ ଭାଷା"</string>
@@ -2045,14 +2044,13 @@
     <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>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ଗୋଟିଏ-ଥର ଆକ୍ସେସ ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍‌କୁ ଦେଖାଇବା ପାଇଁ ଚାହେଁ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ଏଡିଟ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 7cf2acc..2ffeef4 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ਹੱਦੋਂ ਵੱਧ ਕੋਸ਼ਿਸ਼ਾਂ। ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ।"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ਨਿਸ਼ਾਨਬੱਧ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
     <string name="selected" msgid="6614607926197755875">"ਚੁਣਿਆ ਗਿਆ"</string>
     <string name="not_selected" msgid="410652016565864475">"ਨਹੀਂ ਚੁਣਿਆ ਗਿਆ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} ਵਿੱਚੋਂ ਇੱਕ ਤਾਰਾ}one{{max} ਵਿੱਚੋਂ # ਤਾਰਾ}other{{max} ਵਿੱਚੋਂ # ਤਾਰੇ}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ਜਾਰੀ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ਇਸਨੂੰ ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$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">"ਫ਼ੋਨ ਕਰੋ"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ਖੇਤਰ ਤਰਜੀਹ"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"ਭਾਸ਼ਾ ਦਾ ਨਾਮ ਟਾਈਪ ਕਰੋ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"ਸੁਝਾਈਆਂ ਗਈਆਂ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"ਸੁਝਾਈਆਂ ਗਈਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"ਸੁਝਾਏ ਗਏ ਖੇਤਰ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ਸਾਰੀਆਂ ਭਾਸ਼ਾਵਾਂ"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"ਕੀ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ਇੱਕ-ਵਾਰ ਲਈ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ਦੀ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੀ ਇੱਛਾ ਹੈ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"ਕਿਰਿਆਸ਼ੀਲ ਐਪਾਂ ਦੀ ਜਾਂਚ ਕਰੋ"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਫ਼ੋਨ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਟੈਬਲੈੱਟ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ਕਾਰਡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 89c9f31..88b54b0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Zbyt wiele prób. Czytnik linii papilarnych został wyłączony."</string>
+    <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>
@@ -636,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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nie wybrano"</string>
     <string name="selected" msgid="6614607926197755875">"wybrano"</string>
     <string name="not_selected" msgid="410652016565864475">"nie wybrano"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 gwiazdka na {max}}few{# gwiazdki na {max}}many{# gwiazdek na {max}}other{# gwiazdki na {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"w toku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Wykonaj czynność przez..."</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Wykonaj czynność w aplikacji %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Ustawienie regionu"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Wpisz nazwę języka"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugerowane"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerowane"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Sugerowane języki"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Sugerowane regiony"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Wszystkie języki"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Zezwolić aplikacji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> na dostęp do wszystkich dzienników urządzenia?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Zezwól na jednorazowy dostęp"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nie zezwalaj"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Dzienniki urządzenia zapisują, co dzieje się na urządzeniu. Aplikacje mogą ich używać do wykrywania i rozwiązywania problemów.\n\nNiektóre dzienniki mogą zawierać poufne dane, dlatego na dostęp do wszystkich dzienników zezwalaj tylko aplikacjom, którym ufasz. \n\nNawet jeśli nie zezwolisz tej aplikacji na dostęp do wszystkich dzienników na urządzeniu, będzie mogła korzystać z własnych. Producent urządzenia nadal będzie mógł używać niektórych dzienników na urządzeniu."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nie pokazuj ponownie"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacja <xliff:g id="APP_0">%1$s</xliff:g> chce pokazywać wycinki z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edytuj"</string>
@@ -2295,8 +2293,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Sprawdź aktywne aplikacje"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nie można korzystać z aparatu telefonu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nie można korzystać z aparatu tabletu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Nie można z tego skorzystać podczas strumieniowania. Użyj telefonu."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Ustawienie domyślne systemu"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d841ece..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Excesso de tentativas. Sensor de impressão digital desativado."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugestões"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regiões sugeridas"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que o app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acesse todos os registros do dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir o acesso único"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2112,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 08519d8..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Demasiadas tentativas. Sensor de impressões digitais desativado."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1426,7 +1427,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"Explorar"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Saída do interruptor"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> em falta"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"Volte a inserir o dispositivo."</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"Volte a inserir o dispositivo"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"A mover <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"A mover dados"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"Transf. de conteúdo concluída"</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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugeridas"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regiões sugeridas"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que a app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> aceda a todos os registos do dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acesso único"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os registos do dispositivo documentam o que ocorre no seu dispositivo. As apps podem usar esses registos para detetar e corrigir problemas.\n\nAlguns registos podem conter informações confidenciais e, por isso, o acesso a todos os registos do dispositivo deve apenas ser permitido às apps nas quais confia. \n\nSe não permitir o acesso desta app a todos os registos do dispositivo, esta pode ainda assim aceder aos próprios registos. O fabricante do dispositivo pode continuar a aceder a alguns registos ou informações no seu dispositivo."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar de novo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>."</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2112,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 d841ece..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,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Excesso de tentativas. Sensor de impressão digital desativado."</string>
+    <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>
@@ -634,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>
@@ -1084,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>
@@ -1111,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>
@@ -1167,8 +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>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <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>
@@ -1925,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Digitar nome do idioma"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugeridos"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugestões"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Idiomas sugeridos"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regiões sugeridas"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Todos os idiomas"</string>
@@ -2001,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>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Permitir que o app <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> acesse todos os registros do dispositivo?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir o acesso único"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
@@ -2112,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 88c1af8..27b04d6 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -606,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Prea multe încercări. Senzorul de amprentă este dezactivat."</string>
+    <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>
@@ -635,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>
@@ -965,7 +966,7 @@
     <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Pentru a debloca, conectați-vă folosind Contul Google."</string>
     <string name="lockscreen_glogin_username_hint" msgid="6916101478673157045">"Nume de utilizator (e-mail)"</string>
     <string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Parolă"</string>
-    <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Conectați-vă"</string>
+    <string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Conectează-te"</string>
     <string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Nume de utilizator sau parolă nevalide."</string>
     <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Se verifică..."</string>
@@ -1168,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nebifat"</string>
     <string name="selected" msgid="6614607926197755875">"selectat"</string>
     <string name="not_selected" msgid="410652016565864475">"neselectat"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{O stea din {max}}few{# stele din {max}}other{# de stele din {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"în curs"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Finalizare acțiune utilizând"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Finalizați acțiunea utilizând %1$s"</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>
@@ -1655,7 +1655,7 @@
     <string name="kg_login_instructions" msgid="3619844310339066827">"Pentru a debloca, conectați-vă cu Contul dvs. Google."</string>
     <string name="kg_login_username_hint" msgid="1765453775467133251">"Nume de utilizator (e-mail)"</string>
     <string name="kg_login_password_hint" msgid="3330530727273164402">"Parolă"</string>
-    <string name="kg_login_submit_button" msgid="893611277617096870">"Conectați-vă"</string>
+    <string name="kg_login_submit_button" msgid="893611277617096870">"Conectează-te"</string>
     <string name="kg_login_invalid_input" msgid="8292367491901220210">"Nume de utilizator sau parolă nevalide."</string>
     <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Ați uitat numele de utilizator sau parola?\nAccesați "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="4676010303243317253">"Se verifică contul…"</string>
@@ -1926,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Regiunea preferată"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Numele limbii"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugerate"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Sugerate"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Limbi sugerate"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Regiuni sugerate"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Toate limbile"</string>
@@ -2052,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Permiteți ca <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> să acceseze toate jurnalele dispozitivului?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permiteți accesul o dată"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nu permiteți"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Jurnalele dispozitivului înregistrează activitatea de pe dispozitivul tău. Aplicațiile pot folosi aceste jurnale pentru a identifica și a remedia probleme.\n\nUnele jurnale pot să conțină informații sensibile, prin urmare permite accesul la toate jurnalele dispozitivului doar aplicațiilor în care ai încredere. \n\nDacă nu permiți accesul aplicației la toate jurnalele dispozitivului, aceasta poate în continuare să acceseze propriile jurnale. Este posibil ca producătorul dispozitivului să acceseze în continuare unele jurnale sau informații de pe dispozitiv."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nu mai afișa"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 98bac2f..2cceafc 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Слишком много попыток. Сканер отпечатков пальцев отключен."</string>
+    <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 +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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string>
     <string name="selected" msgid="6614607926197755875">"выбрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не выбрано"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Одна звезда из {max}}one{# звезда из {max}}few{# звезды из {max}}many{# звезд из {max}}other{# звезды из {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"в процессе"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Что использовать?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Выполнить с помощью приложения \"%1$s\""</string>
@@ -1427,7 +1427,7 @@
     <string name="ext_media_unmount_action" msgid="966992232088442745">"Извлечь"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"Обзор"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Сменить устройство вывода"</string>
-    <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> не найден"</string>
+    <string name="ext_media_missing_title" msgid="3209472091220515046">"Устройство \"<xliff:g id="NAME">%s</xliff:g>\" не найдено"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"Подключите накопитель снова."</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"Перенос приложения <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Перенос данных"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Региональные настройки"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Введите название языка"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Рекомендуемые"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Доступные регионы"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Рекомендуемые языки"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Предлагаемые регионы"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Все языки"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Разрешить приложению \"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>\" доступ ко всем журналам устройства?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Разрешить разовый доступ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Запретить"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"В журналы записывается информация о том, что происходит на устройстве. Приложения могут использовать их, чтобы находить и устранять неполадки.\n\nТак как некоторые журналы могут содержать конфиденциальную информацию, доступ ко всем журналам следует предоставлять только тем приложениям, которым вы доверяете. \n\nЕсли вы не предоставите такой доступ этому приложению, оно по-прежнему сможет просматривать свои журналы. Не исключено, что некоторые журналы или сведения на вашем устройстве будут по-прежнему доступны его производителю."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Больше не показывать"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Приложение \"<xliff:g id="APP_0">%1$s</xliff:g>\" запрашивает разрешение на показ фрагментов приложения \"<xliff:g id="APP_2">%2$s</xliff:g>\"."</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Изменить"</string>
@@ -2295,8 +2293,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Проверить активные приложения"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере телефона."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере планшета."</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Этот контент недоступен во время трансляции. Используйте телефон."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Системные настройки по умолчанию"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index a2979e4..06ac0f8 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"උත්සාහයන් ඉතා වැඩි ගණනකි. ඇඟිලි සලකුණු සංවේදකය අබල කරන ලදී."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"පරීක්ෂා කර නැත"</string>
     <string name="selected" msgid="6614607926197755875">"තෝරන ලදි"</string>
     <string name="not_selected" msgid="410652016565864475">"තෝරා නොමැත"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}න් එක තරුවක්}one{{max}න් තරු #ක්}other{{max}න් තරු #ක්}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"සිදු වෙමින් පවතී"</string>
     <string name="whichApplication" msgid="5432266899591255759">"පහත භාවිතයෙන් ක්‍රියාව සම්පූර්ණ කරන්න"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s භාවිතා කරමින් ක්‍රියාව සම්පුර්ණ කරන්න"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ප්‍රදේශ මනාපය"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"භාෂා නම ටයිප් කරන්න"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"යෝජිත"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"යෝජිත"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"යෝජිත භාෂා"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"යෝජිත කලාප"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"සියලු භාෂා"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> හට සියලු උපාංග ලොග ප්‍රවේශ වීමට ඉඩ දෙන්නද?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"එක් වරක් ප්‍රවේශය ඉඩ දෙන්න"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ඉඩ නොදෙන්න"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"උපාංග ලොග ඔබේ උපාංගයෙහි සිදු වන දේ වාර්තා කරයි. ගැටලු සොයා ගැනීමට සහ නිරාකරණයට යෙදුම්වලට මෙම ලොග භාවිතා කළ හැක.\n\nසමහර ලොගවල සංවේදී තතු අඩංගු විය හැකි බැවින්, ඔබ විශ්වාස කරන යෙදුම්වලට පමණක් සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න. \n\nඔබ මෙම යෙදුමට සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ නොදෙන්නේ නම්, එයට තවමත් එහිම ලොග වෙත ප්‍රවේශ විය හැක. ඔබේ උපාංග නිෂ්පාදකයාට තවමත් ඔබේ උපාංගයෙහි සමහර ලොග හෝ තතු වෙත ප්‍රවේශ විය හැක."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"නැවත නොපෙන්වන්න"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> හට කොටස් <xliff:g id="APP_2">%2$s</xliff:g>ක් පෙන්වීමට අවශ්‍යයි"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"සංස්කරණය"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"සක්‍රිය යෙදුම් පරීක්ෂා කරන්න"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් දුරකථනයේ කැමරාවට ප්‍රවේශ විය නොහැකිය"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් ටැබ්ලටයේ කැමරාවට ප්‍රවේශ විය නොහැකිය"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"ප්‍රවාහය කරන අතරේ මෙයට ප්‍රවේශ විය නොහැක. ඒ වෙනුවට ඔබේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
     <string name="system_locale_title" msgid="711882686834677268">"පද්ධති පෙරනිමිය"</string>
     <string name="default_card_name" msgid="9198284935962911468">"කාඩ්පත <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c23f839..cdc6829 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Príliš veľa pokusov. Senzor odtlačkov prstov bol deaktivovaný."</string>
+    <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>
@@ -636,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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nezačiarknuté"</string>
     <string name="selected" msgid="6614607926197755875">"vybrané"</string>
     <string name="not_selected" msgid="410652016565864475">"nevybrané"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 hviezdička z {max}}few{# hviezdičky z {max}}many{# hviezdičky z {max}}other{# hviezdičiek z {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"prebieha"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončiť akciu pomocou aplikácie"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončiť akciu pomocou aplikácie %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferovaný región"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Zadajte názov jazyka"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Navrhované"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Navrhované"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Navrhované jazyky"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Navrhované oblasti"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Všetky jazyky"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Chcete povoliť aplikácii <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> prístup k všetkým denníkom zariadenia?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Povoliť jednorazový prístup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovoliť"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Denníky zariadenia zaznamenávajú, čo sa deje vo vašom zariadení. Aplikácie môžu pomocou týchto denníkov vyhľadávať a riešiť problémy.\n\nNiektoré denníky môžu obsahovať citlivé údaje, preto povoľte prístup k všetkým denníkom zariadenia iba dôveryhodným aplikáciám. \n\nAk tejto aplikácii nepovolíte prístup k všetkým denníkom zariadenia, stále bude mať prístup k vlastným denníkom. Výrobca vášho zariadenia bude mať naďalej prístup k niektorým denníkom alebo informáciám vo vašom zariadení."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Už nezobrazovať"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Upraviť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 99986c3..6da07f8 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Preveč poskusov. Tipalo prstnih odtisov je onemogočeno."</string>
+    <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>
@@ -636,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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ni potrjeno"</string>
     <string name="selected" msgid="6614607926197755875">"izbrano"</string>
     <string name="not_selected" msgid="410652016565864475">"ni izbrano"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Ena zvezdica od {max}}one{# zvezdica od {max}}two{# zvezdici od {max}}few{# zvezdice od {max}}other{# zvezdic od {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"v teku"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z aplikacijo"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončanje dejanja z aplikacijo %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Nastavitev območja"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Vnesite ime jezika"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Predlagano"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Predlagano"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Predlagani jeziki"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Predlagana območja"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Vsi jeziki"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Ali aplikaciji <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> dovolite dostop do vseh dnevnikov naprave?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dovoli enkratni dostop"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dovoli"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"V dnevnikih naprave se beleži dogajanje v napravi. Aplikacije lahko te dnevnike uporabijo za iskanje in odpravljanje težav.\n\nNekateri dnevniki morda vsebujejo občutljive podatke, zato dostop do vseh dnevnikov naprave omogočite le aplikacijam, ki jim zaupate. \n\nČe tej aplikaciji ne dovolite dostopa do vseh dnevnikov naprave, bo aplikacija kljub temu lahko dostopala do svojih dnevnikov. Proizvajalec naprave bo morda lahko kljub temu dostopal do nekaterih dnevnikov ali podatkov v napravi."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikaži več"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati izreze aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
@@ -2295,8 +2293,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Preverite aktivne aplikacije"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ni mogoče dostopati do fotoaparata telefona prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ni mogoče dostopati do fotoaparata tabličnega računalnika prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Do te vsebine ni mogoče dostopati med pretočnim predvajanjem. Poskusite s telefonom."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistemsko privzeto"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 93ae3e8..587215a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Shumë përpjekje. Sensori i gjurmës së gishtit u çaktivizua."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"nuk u përzgjodh"</string>
     <string name="selected" msgid="6614607926197755875">"i zgjedhur"</string>
     <string name="not_selected" msgid="410652016565864475">"i pazgjedhur"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Një yll nga {max}}other{# yje nga {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"në vazhdim"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Përfundo veprimin duke përdorur"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Përfundo veprimin duke përdorur %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Preferenca e rajonit"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Shkruaj emrin e gjuhës"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Sugjeruar"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Të sugjeruara"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Gjuhët e sugjeruara"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Rajonet e sugjeruara"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Të gjitha gjuhët"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Të lejohet që <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> të ketë qasje te të gjitha evidencat e pajisjes?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Lejo qasjen vetëm për një herë"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Mos lejo"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Evidencat e pajisjes regjistrojnë çfarë ndodh në pajisjen tënde. Aplikacionet mund t\'i përdorin këto evidenca për të gjetur dhe rregulluar problemet.\n\nDisa evidenca mund të përmbajnë informacione delikate, ndaj lejo vetëm aplikacionet që u beson të kenë qasje te të gjitha evidencat e pajisjes. \n\nNëse nuk e lejon këtë aplikacion që të ketë qasje te të gjitha evidencat e pajisjes, ai mund të vazhdojë të ketë qasje tek evidencat e tij. Prodhuesi i pajisjes sate mund të jetë ende në gjendje që të ketë qasje te disa evidenca ose informacione në pajisjen tënde."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Mos e shfaq më"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> dëshiron të shfaqë pjesë të <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Modifiko"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollo aplikacionet aktive"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nuk mund të qasesh në kamerën e telefonit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nuk mund të qasesh në kamerën e tabletit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Nuk mund të kesh qasje në të gjatë transmetimit. Provoje në telefon më mirë."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Parazgjedhja e sistemit"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6f0fc17..2acaf5c 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -606,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Превише покушаја. Сензор за отисак прста је онемогућен."</string>
+    <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 +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>
@@ -1168,8 +1169,7 @@
     <string name="not_checked" msgid="7972320087569023342">"није означено"</string>
     <string name="selected" msgid="6614607926197755875">"изабрано"</string>
     <string name="not_selected" msgid="410652016565864475">"није изабрано"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Једна звездица од {max}}one{# звездица од {max}}few{# звездице од {max}}other{# звездица од {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"у току"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Доврши радњу преко"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завршите радњу помоћу апликације %1$s"</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>
@@ -1926,8 +1926,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Подешавање региона"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Унесите назив језика"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Предложени"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Предложено"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Предложени језици"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Предложени региони"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Сви језици"</string>
@@ -2052,8 +2051,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Желите да дозволите апликацији <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> да приступа свим евиденцијама уређаја?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дозволи једнократан приступ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволи"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не приказуј поново"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Апликација <xliff:g id="APP_0">%1$s</xliff:g> жели да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index a5515b1..a6c162a 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -237,7 +237,7 @@
     <string name="global_actions" product="default" msgid="6410072189971495460">"Telefonalternativ"</string>
     <string name="global_action_lock" msgid="6949357274257655383">"Skärmlås"</string>
     <string name="global_action_power_off" msgid="4404936470711393203">"Stäng av"</string>
-    <string name="global_action_power_options" msgid="1185286119330160073">"Strömbrytare"</string>
+    <string name="global_action_power_options" msgid="1185286119330160073">"Av/på"</string>
     <string name="global_action_restart" msgid="4678451019561687074">"Starta om"</string>
     <string name="global_action_emergency" msgid="1387617624177105088">"Nödsituation"</string>
     <string name="global_action_bug_report" msgid="5127867163044170003">"Felrapport"</string>
@@ -605,13 +605,13 @@
     <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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Du har försökt för många gånger. Fingeravtryckssensorn har inaktiverats."</string>
+    <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>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Sensorn har tillfälligt inaktiverats."</string>
     <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Det går inte att använda fingeravtryckssensorn. Besök ett reparationsställe"</string>
-    <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Strömbrytaren nedtryckt"</string>
+    <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"Av/på-knappen nedtryckt"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Finger <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Använd ditt fingeravtryck"</string>
     <string name="fingerprint_or_screen_lock_app_setting_name" msgid="3501743523487644907">"Använd ditt fingeravtryck eller skärmlåset"</string>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"inte markerad"</string>
     <string name="selected" msgid="6614607926197755875">"valt"</string>
     <string name="not_selected" msgid="410652016565864475">"inte valt"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{En stjärna av {max}}other{# stjärnor av {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"pågår"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Slutför åtgärd genom att använda"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Slutför åtgärden med %1$s"</string>
@@ -1248,11 +1248,11 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> förbereds."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Appar startas."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Uppgraderingen är klar."</string>
-    <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du tryckte på strömbrytaren, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt när du konfigurerar fingeravtrycket."</string>
+    <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Du tryckte på av/på-knappen, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt när du konfigurerar fingeravtrycket."</string>
     <string name="fp_power_button_enrollment_title" msgid="8997641910928785172">"Tryck för att stänga av skärmen"</string>
     <string name="fp_power_button_enrollment_button_text" msgid="8351290204990805109">"Stäng av skärmen"</string>
     <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Vill du verifiera ditt fingeravtryck?"</string>
-    <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du tryckte på strömbrytaren, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt för att verifiera ditt fingeravtryck."</string>
+    <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Du tryckte på av/på-knappen, vilket vanligtvis stänger av skärmen.\n\nTesta att trycka lätt för att verifiera ditt fingeravtryck."</string>
     <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Stäng av skärmen"</string>
     <string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"Fortsätt"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"<xliff:g id="APP">%1$s</xliff:g> körs"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Regionsinställningar"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Ange språk"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Förslag"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Förslag"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Föreslagna språk"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Föreslagna regioner"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Alla språk"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Vill du tillåta att <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> får åtkomst till alla enhetsloggar?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tillåt engångsåtkomst"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillåt inte"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"I enhetsloggar registreras vad som händer på enheten. Appar kan använda dessa loggar för att hitta och åtgärda problem.\n\nVissa loggar kan innehålla känsliga uppgifter, så du ska bara bevilja appar du litar på åtkomst till alla enhetsloggar. \n\nEn app har åtkomst till sina egna loggar även om du inte ger den åtkomst till alla enhetsloggar. Enhetens tillverkare kan fortfarande ha åtkomst till vissa loggar eller viss information på enheten."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Visa inte igen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vill kunna visa bitar av <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Redigera"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Kontrollera aktiva appar"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Telefonens kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Surfplattans kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Det går inte att komma åt innehållet när du streamar. Testa med telefonen i stället."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Systemets standardinställning"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0552c2c..b17f58e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Majaribio mengi mno. Kitambua alama ya kidole kimezimwa."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"haijateuliwa"</string>
     <string name="selected" msgid="6614607926197755875">"imechaguliwa"</string>
     <string name="not_selected" msgid="410652016565864475">"haijachaguliwa"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Nyota moja kati ya {max}}other{Nyota # kati ya {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"inaendelea"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Kamilisha kitendo ukitumia"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Kamilisha kitendo ukitumia %1$s"</string>
@@ -1566,7 +1566,7 @@
     <string name="action_bar_home_subtitle_description_format" msgid="4346835454749569826">"%1$s, %2$s, %3$s"</string>
     <string name="storage_internal" msgid="8490227947584914460">"Hifadhi ya ndani ya pamoja"</string>
     <string name="storage_sd_card" msgid="3404740277075331881">"Kadi ya SD"</string>
-    <string name="storage_sd_card_label" msgid="7526153141147470509">"Kadi ya SD iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
+    <string name="storage_sd_card_label" msgid="7526153141147470509">"Kadi ya SD ya <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb_drive" msgid="448030813201444573">"Hifadhi ya USB"</string>
     <string name="storage_usb_drive_label" msgid="6631740655876540521">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
     <string name="storage_usb" msgid="2391213347883616886">"Hifadhi ya USB"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Mapendeleo ya eneo"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Weka jina la lugha"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Zinazopendekezwa"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Yanayopendekezwa"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Lugha zinazopendekezwa"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Maeneo yanayopendekezwa"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Lugha zote"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Ungependa kuruhusu <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ifikie kumbukumbu zote za kifaa?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Ruhusu ufikiaji wa mara moja"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Usiruhusu"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Kumbukumbu za kifaa zinarekodi kinachofanyika kwenye kifaa chako. Programu zinaweza kutumia kumbukumbu hizi ili kutambua na kurekebisha hitilafu.\n\nBaadhi ya kumbukumbu huenda zikawa na taarifa nyeti, hivyo ruhusu tu programu unazoziamini kufikia kumbukumbu zote za kifaa. \n\nIwapo hutaruhusu programu hii ifikie kumbukumbu zote za kifaa, bado inaweza kufikia kumbukumbu zake yenyewe. Huenda mtengenezaji wa kifaa chako bado akaweza kufikia baadhi ya kumbukumbu au taarifa zilizopo kwenye kifaa chako."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Usionyeshe tena"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> inataka kuonyesha vipengee <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Badilisha"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Angalia programu zinazotumika"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Haiwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Haiwezi kufikia kamera ya kompyuta kibao kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Huwezi kufikia maudhui haya unapotiririsha. Badala yake jaribu kwenye simu yako."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Chaguomsingi la mfumo"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SIM KADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 21c457b..6a7973e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"பலமுறை முயன்றுவிட்டீர்கள். கைரேகை சென்சார் முடக்கப்பட்டது."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"முடக்கப்பட்டுள்ளது"</string>
     <string name="selected" msgid="6614607926197755875">"தேர்ந்தெடுக்கப்பட்டது"</string>
     <string name="not_selected" msgid="410652016565864475">"தேர்ந்தெடுக்கப்படவில்லை"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{ஒரு நட்சத்திரம்/{max}}other{# நட்சத்திரங்கள்/{max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"செயலிலுள்ளது"</string>
     <string name="whichApplication" msgid="5432266899591255759">"இதைப் பயன்படுத்தி செயலை நிறைவுசெய்"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ஐப் பயன்படுத்தி செயலை முடிக்கவும்"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"மண்டல விருப்பம்"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"மொழி பெயரை உள்ளிடுக"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"பரிந்துரைகள்"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"பரிந்துரைக்கப்படுபவை"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"பரிந்துரைக்கப்படும் மொழிகள்"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"பரிந்துரைக்கப்படும் பகுதிகள்"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"எல்லா மொழிகளும்"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"சாதனப் பதிவுகள் அனைத்தையும் <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> அணுக அனுமதிக்கவா?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ஒருமுறை அணுகலை அனுமதி"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"அனுமதிக்க வேண்டாம்"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸ் இந்தப் பதிவுகளைப் பயன்படுத்தலாம்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள் சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக நீங்கள் நம்பும் ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"மீண்டும் காட்டாதே"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"திருத்து"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 6ae3f21..8c53b13 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"అనేకసార్లు ప్రయత్నించారు. వేలిముద్ర సెన్సార్ నిలిపివేయబడింది."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ఎంచుకోలేదు"</string>
     <string name="selected" msgid="6614607926197755875">"ఎంచుకోబడింది"</string>
     <string name="not_selected" msgid="410652016565864475">"ఎంచుకోబడలేదు"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max}కి ఒక స్టార్}other{{max}కి # స్టార్‌లు}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"ప్రోగ్రెస్‌లో ఉంది"</string>
     <string name="whichApplication" msgid="5432266899591255759">"దీన్ని ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sను ఉపయోగించి చర్యను పూర్తి చేయి"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ప్రాంతం ప్రాధాన్యత"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"భాష పేరును టైప్ చేయండి"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"సూచించినవి"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"సూచించబడినవి"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"సూచించిన భాషలు"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"సూచించిన ప్రాంతాలు"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"అన్ని భాషలు"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>‌ను అనుమతించాలా?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"వన్-టైమ్ యాక్సెస్‌ను అనుమతించండి"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"అనుమతించవద్దు"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్‌లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్‌లు ఈ లాగ్‌లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్‌లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్‌లను మాత్రమే అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్‌ను అనుమతించకపోతే, అది తన స్వంత లాగ్‌లను ఇప్పటికి యాక్సెస్ చేయగలదు. మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్‌లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"మళ్లీ చూపవద్దు"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> స్లైస్‌లను చూపించాలనుకుంటోంది"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ఎడిట్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index e490f70..7826774 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"ลองหลายครั้งเกินไป ปิดใช้เซ็นเซอร์ลายนิ้วมือแล้ว"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"ยังไม่เลือก"</string>
     <string name="selected" msgid="6614607926197755875">"เลือกไว้"</string>
     <string name="not_selected" msgid="410652016565864475">"ไม่ได้เลือกไว้"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 จาก {max} ดาว}other{# จาก {max} ดาว}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"กำลังดำเนินการ"</string>
     <string name="whichApplication" msgid="5432266899591255759">"ทำงานให้เสร็จโดยใช้"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"ดำเนินการให้เสร็จสมบูรณ์โดยใช้ %1$s"</string>
@@ -1425,7 +1425,7 @@
     <string name="ext_media_unmount_action" msgid="966992232088442745">"นำอุปกรณ์ออก"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"สำรวจ"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"เปลี่ยนเอาต์พุต"</string>
-    <string name="ext_media_missing_title" msgid="3209472091220515046">"ไม่มี <xliff:g id="NAME">%s</xliff:g>"</string>
+    <string name="ext_media_missing_title" msgid="3209472091220515046">"ไม่มี<xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"ใส่อุปกรณ์อีกครั้ง"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"กำลังย้าย <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"กำลังย้ายข้อมูล"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"ค่ากำหนดภูมิภาค"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"พิมพ์ชื่อภาษา"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"แนะนำ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"แนะนำ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"ภาษาที่แนะนำ"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"ภูมิภาคที่แนะนำ"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"ทุกภาษา"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"อนุญาตให้ <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> เข้าถึงบันทึกทั้งหมดของอุปกรณ์ใช่ไหม"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"อนุญาตสิทธิ์เข้าถึงแบบครั้งเดียว"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ไม่อนุญาต"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ \n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ของคุณได้"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ไม่ต้องแสดงอีก"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ต้องการแสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"แก้ไข"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b78380c..e9d17a9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Masyadong maraming beses sumubok. Na-disable ang sensor para sa fingerprint."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"hindi nilagyan ng check"</string>
     <string name="selected" msgid="6614607926197755875">"pinili"</string>
     <string name="not_selected" msgid="410652016565864475">"hindi pinili"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Isang star sa {max}}one{# star sa {max}}other{# na star sa {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"isinasagawa"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Kumpletuhin ang pagkilos gamit ang"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Tapusin ang pagkilos gamit ang %1$s"</string>
@@ -1426,7 +1426,7 @@
     <string name="ext_media_browse_action" msgid="344865351947079139">"I-explore"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Ilipat ang output"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"Nawawala ang <xliff:g id="NAME">%s</xliff:g>"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"Ikabit muli ang device"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"Ikabit ulit ang device"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"Inililipat ang <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Naglilipat ng data"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"Tapos na ang paglipat ng content"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Kagustuhan sa rehiyon"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"I-type ang wika"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Iminumungkahi"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Iminumungkahi"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Mga iminumungkahing wika"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Mga iminumungkahing rehiyon"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Lahat ng wika"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Payagan ang <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> na i-access ang lahat ng log ng device?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Payagan ang isang beses na pag-access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Huwag payagan"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Nire-record ng mga log ng device kung ano ang nangyayari sa iyong device. Magagamit ng mga app ang mga log na ito para maghanap at mag-ayos ng mga isyu.\n\nPosibleng maglaman ang ilang log ng sensitibong impormasyon, kaya ang mga app lang na pinagkakatiwalaan mo ang payagang maka-access sa lahat ng log ng device. \n\nKung hindi mo papayagan ang app na ito na i-access ang lahat ng log ng device, maa-access pa rin nito ang mga sarili nitong log. Posible pa ring ma-access ng manufacturer ng iyong device ang ilang log o impormasyon sa device mo."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Huwag ipakita ulit"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Gustong ipakita ng <xliff:g id="APP_0">%1$s</xliff:g> ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"I-edit"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7c4c6e4..762b731 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Çok fazla deneme yapıldı. Parmak izi sensörü devre dışı bırakıldı."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"işaretli değil"</string>
     <string name="selected" msgid="6614607926197755875">"seçili"</string>
     <string name="not_selected" msgid="410652016565864475">"seçili değil"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} üzerinden bir yıldız}other{{max} üzerinden # yıldız}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"devam ediyor"</string>
     <string name="whichApplication" msgid="5432266899591255759">"İşlemi şunu kullanarak tamamla"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"İşlemi %1$s kullanarak tamamla"</string>
@@ -1594,7 +1594,7 @@
     <string name="validity_period" msgid="1717724283033175968">"Geçerlilik:"</string>
     <string name="issued_on" msgid="5855489688152497307">"Yayınlanma tarihi:"</string>
     <string name="expires_on" msgid="1623640879705103121">"Sona erme tarihi:"</string>
-    <string name="serial_number" msgid="3479576915806623429">"Seri numara:"</string>
+    <string name="serial_number" msgid="3479576915806623429">"Seri numarası:"</string>
     <string name="fingerprints" msgid="148690767172613723">"Parmak izleri:"</string>
     <string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 parmak izi:"</string>
     <string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1 parmak izi:"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Bölge tercihi"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Dil adını yazın"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Önerilen"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Önerilen"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Önerilen diller"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Önerilen bölgeler"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Tüm diller"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> uygulamasının tüm cihaz günlüklerine erişmesine izin verilsin mi?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tek seferlik erişim izni ver"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"İzin verme"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Cihaz günlükleri, cihazınızda olanları kaydeder. Uygulamalar, sorunları bulup düzeltmek için bu günlükleri kullanabilir.\n\nBazı günlükler hassas bilgiler içerebileceği için yalnızca güvendiğiniz uygulamaların tüm cihaz günlüklerine erişmesine izin verin. \n\nBu uygulamanın tüm cihaz günlüklerine erişmesine izin vermeseniz de kendi günlüklerine erişmeye devam edebilir. Ayrıca, cihaz üreticiniz de cihazınızdaki bazı günlüklere veya bilgilere erişmeye devam edebilir."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Bir daha gösterme"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> uygulaması, <xliff:g id="APP_2">%2$s</xliff:g> dilimlerini göstermek istiyor"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Düzenle"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Etkin uygulamaları kontrol edin"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına erişilemiyor"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan tabletin kamerasına erişilemiyor"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Canlı oynatılırken bu içeriğe erişilemez. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistem varsayılanı"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 747e9a8..730cfac 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -607,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Забагато спроб. Сканер відбитків пальців вимкнено."</string>
+    <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 +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>
@@ -1169,8 +1170,7 @@
     <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string>
     <string name="selected" msgid="6614607926197755875">"вибрано"</string>
     <string name="not_selected" msgid="410652016565864475">"не вибрано"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Одна зірочка з {max}}one{# зірочка з {max}}few{# зірочки з {max}}many{# зірочок із {max}}other{# зірочки з {max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"триває"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Що використовувати?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Завершити дію за допомогою %1$s"</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>
@@ -1927,8 +1927,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Вибір регіону"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Введіть назву мови"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Рекомендовані"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Пропоновані"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Пропоновані мови"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Пропоновані регіони"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Усі мови"</string>
@@ -2053,8 +2052,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Надати додатку <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> доступ до всіх журналів пристрою?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Надати доступ лише цього разу"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволяти"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"У журналах пристрою реєструється все, що відбувається на ньому. За допомогою цих журналів додатки можуть виявляти й усувати проблеми.\n\nДеякі журнали можуть містити конфіденційні дані, тому надавати доступ до всіх журналів пристрою слід лише надійним додаткам. \n\nЯкщо додаток не має доступу до всіх журналів пристрою, він усе одно може використовувати власні журнали. Виробник вашого пристрою все одно може використовувати деякі журнали чи інформацію на ньому."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Більше не показувати"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> хоче показати фрагменти додатка <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Редагувати"</string>
@@ -2295,8 +2293,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Перевірте активні додатки"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не вдається отримати доступ до камери телефона з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не вдається отримати доступ до камери планшета з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Цей контент недоступний під час потокового передавання. Спробуйте натомість скористатися телефоном."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Налаштування системи за умовчанням"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7e2b994..6fa0071 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"کافی زیادہ کوششیں۔ فنگر پرنٹ سینسر غیر فعال ہو گیا۔"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"چیک نہیں کیا گیا"</string>
     <string name="selected" msgid="6614607926197755875">"منتخب کردہ"</string>
     <string name="not_selected" msgid="410652016565864475">"غیر منتخب کردہ"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{{max} میں سے ایک ستارہ}other{{max} میں سے # ستارے}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"جاری ہے"</string>
     <string name="whichApplication" msgid="5432266899591255759">"اس کا استعمال کرکے کارروائی مکمل کریں"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"‏%1$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">"فون"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"علاقہ کی ترجیح"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"زبان کا نام ٹائپ کریں"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"تجویز کردہ"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"تجویز کردہ"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"تجویز کردہ زبانیں"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"تجویز کردہ علاقے"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"سبھی زبانیں"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> کو آلے کے تمام لاگز تک رسائی کی اجازت دیں؟"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"یک وقتی رسائی کی اجازت دیں"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"اجازت نہ دیں"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"آپ کے آلے پر جو ہوتا ہے آلے کے لاگز اسے ریکارڈ کر لیتے ہیں۔ ایپس ان لاگز کا استعمال مسائل کو تلاش کرنے اور ان کو حل کرنے کے لیے کر سکتی ہیں۔\n\nکچھ لاگز میں حساس معلومات شامل ہو سکتی ہیں، اس لیے صرف اپنے بھروسے مند ایپس کو ہی آلے کے تمام لاگز تک رسائی کی اجازت دیں۔ \n\nاگر آپ اس ایپ کو آلے کے تمام لاگز تک رسائی کی اجازت نہیں دیتے ہیں تب بھی یہ اپنے لاگز تک رسائی حاصل کر سکتی ہے۔ آپ کے آلے کا مینوفیکچرر اب بھی آپ کے آلے پر کچھ لاگز یا معلومات تک رسائی حاصل کر سکتا ہے۔"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"دوبارہ نہ دکھائیں"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> کے سلائسز دکھانا چاہتی ہے"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ترمیم کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a14a27a..b9a0ae5 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Urinishlar soni ko‘payib ketdi. Barmoq izi skaneri bloklandi."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"belgilanmadi"</string>
     <string name="selected" msgid="6614607926197755875">"tanlangan"</string>
     <string name="not_selected" msgid="410652016565864475">"tanlanmagan"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Maksimal {max} ta yulduzdan 1 yulduz}other{Maksimal {max} ta yulduzdan # yulduz}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"bajarilmoqda"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Nima ishlatilsin?"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"“%1$s” bilan ochish"</string>
@@ -1423,10 +1423,10 @@
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Chiqarib olinmasin"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"Sozlash"</string>
     <string name="ext_media_unmount_action" msgid="966992232088442745">"Chiqarish"</string>
-    <string name="ext_media_browse_action" msgid="344865351947079139">"O‘rganish"</string>
+    <string name="ext_media_browse_action" msgid="344865351947079139">"Ochish"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Audio chiqishni almashtirish"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> topilmadi"</string>
-    <string name="ext_media_missing_message" msgid="4408988706227922909">"Qurilmani yana ulang"</string>
+    <string name="ext_media_missing_message" msgid="4408988706227922909">"Qurilmani qayta ulang"</string>
     <string name="ext_media_move_specific_title" msgid="8492118544775964250">"<xliff:g id="NAME">%s</xliff:g> ko‘chirib o‘tkazilmoqda"</string>
     <string name="ext_media_move_title" msgid="2682741525619033637">"Ma’lumotlar ko‘chirilmoqda"</string>
     <string name="ext_media_move_success_title" msgid="4901763082647316767">"Kontent ko‘chirildi"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Hudud sozlamalari"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Til nomini kiriting"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Taklif etiladi"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Tavsiya etiladi"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Tavsiya etilgan tillar"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Tavsiya etilgan mintaqalar"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Barcha tillar"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ilovasining qurilmadagi barcha jurnallarga kirishiga ruxsat berilsinmi?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Bir matalik foydalanishga ruxsat berish"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Rad etish"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Qurilma jurnaliga qurilma bilan yuz bergan hodisalar qaydlari yoziladi. Ilovalar bu jurnal qaydlari yordamida muammolarni topishi va bartaraf qilishi mumkin.\n\nAyrim jurnal qaydlarida maxfiy axborotlar yozilishi mumkin, shu sababli qurilmadagi barcha jurnal qaydlariga ruxsatni faqat ishonchli ilovalarga bering. \n\nBu ilovaga qurilmadagi barcha jurnal qaydlariga ruxsat berilmasa ham, u oʻzining jurnalini ocha oladi. Qurilma ishlab chiqaruvchisi ham ayrim jurnallar yoki qurilma haqidagi axborotlarni ocha oladi."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Boshqa chiqmasin"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ilovasi <xliff:g id="APP_2">%2$s</xliff:g> ilovasidan fragmentlar ko‘rsatish uchun ruxsat so‘ramoqda"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Tahrirlash"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 39a46ee..ad4a3899 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Quá nhiều lần thử. Cảm biến vân tay đã bị tắt."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"chưa chọn"</string>
     <string name="selected" msgid="6614607926197755875">"đã chọn"</string>
     <string name="not_selected" msgid="410652016565864475">"chưa được chọn"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1/{max} sao}other{#/{max} sao}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"đang thực hiện"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Hoàn tất thao tác bằng"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất thao tác bằng %1$s"</string>
@@ -1422,7 +1422,7 @@
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"Đang ngắt kết nối <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Không tháo"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"Thiết lập"</string>
-    <string name="ext_media_unmount_action" msgid="966992232088442745">"Tháo"</string>
+    <string name="ext_media_unmount_action" msgid="966992232088442745">"Ngắt kết nối"</string>
     <string name="ext_media_browse_action" msgid="344865351947079139">"Khám phá"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Chuyển đổi đầu ra"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> bị thiếu"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Tùy chọn khu vực"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Nhập tên ngôn ngữ"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Đề xuất"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Ðề xuất"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Ngôn ngữ đề xuất"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Khu vực đề xuất"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Tất cả ngôn ngữ"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Cho phép <xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> truy cập vào tất cả các nhật ký thiết bị?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Cho phép truy cập một lần"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Không cho phép"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Nhật ký thiết bị ghi lại những hoạt động diễn ra trên thiết bị. Các ứng dụng có thể dùng nhật ký này để tìm và khắc phục sự cố.\n\nMột số nhật ký có thể chứa thông tin nhạy cảm, vì vậy, bạn chỉ nên cấp quyền truy cập vào toàn bộ nhật ký thiết bị cho những ứng dụng mà mình tin cậy. \n\nNếu bạn không cho phép ứng dụng này truy cập vào toàn bộ nhật ký thiết bị, thì ứng dụng vẫn có thể truy cập vào nhật ký của chính nó. Nhà sản xuất thiết bị vẫn có thể truy cập vào một số nhật ký hoặc thông tin trên thiết bị của bạn."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Không hiện lại"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> muốn hiển thị các lát của <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Chỉnh sửa"</string>
@@ -2293,8 +2291,7 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Xem các ứng dụng đang hoạt động"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Không truy cập được vào máy ảnh trên điện thoại từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Không truy cập được vào máy ảnh trên máy tính bảng từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
-    <!-- no translation found for vdm_secure_window (161700398158812314) -->
-    <skip />
+    <string name="vdm_secure_window" msgid="161700398158812314">"Bạn không thể truy cập vào nội dung này trong khi phát trực tuyến. Hãy thử trên điện thoại."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Theo chế độ mặc định của hệ thống"</string>
     <string name="default_card_name" msgid="9198284935962911468">"THẺ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 3bef669..ce5cd53 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"尝试次数过多。指纹传感器已停用。"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"未勾选"</string>
     <string name="selected" msgid="6614607926197755875">"已选择"</string>
     <string name="not_selected" msgid="410652016565864475">"未选择"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 星,最高 {max} 星}other{# 星,最高 {max} 星}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"进行中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"选择要使用的应用:"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"使用%1$s完成操作"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"区域偏好设置"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"输入语言名称"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"建议语言"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"推荐地区"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"建议的语言"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"建议的地区"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"所有语言"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"允许“<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>”访问所有设备日志吗?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"允许访问一次"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允许"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,它仍然可以访问自己的日志。您的设备制造商可能仍然能够访问设备上的部分日志或信息。"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"不再显示"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"“<xliff:g id="APP_0">%1$s</xliff:g>”想要显示“<xliff:g id="APP_2">%2$s</xliff:g>”图块"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"编辑"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index e541a33..96c7b0b 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"嘗試次數過多,指紋感應器已停用。"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
     <string name="selected" msgid="6614607926197755875">"揀咗"</string>
     <string name="not_selected" msgid="410652016565864475">"未揀"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 顆星 (滿分為 {max} 顆星)}other{# 顆星 (滿分為 {max} 顆星)}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"處理中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"完成操作需使用"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"輸入語言名稱"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"建議"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建議的語言"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"建議的語言"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"建議地區"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"所有語言"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"要允許「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」存取所有裝置記錄嗎?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"允許存取一次"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"裝置記錄會記下裝置上的活動。應用程式可透過這些記錄找出並修正問題。\n\n部分記錄可能包含敏感資料,因此請只允許信任的應用程式存取所有裝置記錄。\n\n如果不允許此應用程式存取所有裝置記錄,此應用程式仍能存取自己的記錄,且裝置製造商可能仍可存取裝置上的部分記錄或資料。"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的快訊"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 81c68e6..46d95c7f 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"嘗試次數過多,指紋感應器已停用。"</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
     <string name="selected" msgid="6614607926197755875">"已選取"</string>
     <string name="not_selected" msgid="410652016565864475">"未選取"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{1 顆星 (滿分為 {max} 顆星)}other{# 顆星 (滿分為 {max} 顆星)}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"處理中"</string>
     <string name="whichApplication" msgid="5432266899591255759">"選擇要使用的應用程式"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"地區偏好設定"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"請輸入語言名稱"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"建議語言"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"建議的語言"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"建議語言"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"建議地區"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"所有語言"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"要允許「<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g>」存取所有裝置記錄嗎?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"允許一次性存取"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"不允許"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"系統會透過裝置記錄記下裝置上的活動。應用程式可以根據這些記錄找出問題並進行修正。\n\n某些記錄可能含有機密資訊,因此請勿讓不信任的應用程式存取所有裝置記錄。\n\n即使你不允許這個應用程式存取所有裝置記錄,這個應用程式仍能存取自己的記錄,而且裝置製造商或許仍可存取裝置的某些記錄或資訊。"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"不要再顯示"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」想要顯示「<xliff:g id="APP_2">%2$s</xliff:g>」的區塊"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"編輯"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 8c115af..6e640c6 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -605,7 +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>
-    <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Imizamo eminingi kakhulu. Inzwa yezigxivizo zeminwe ikhutshaziwe."</string>
+    <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>
@@ -634,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>
@@ -1167,8 +1168,7 @@
     <string name="not_checked" msgid="7972320087569023342">"akuhloliwe"</string>
     <string name="selected" msgid="6614607926197755875">"okukhethiwe"</string>
     <string name="not_selected" msgid="410652016565864475">"akukhethiwe"</string>
-    <!-- no translation found for rating_label (1837085249662154601) -->
-    <skip />
+    <string name="rating_label" msgid="1837085249662154601">"{rating,plural, =1{Inkanyezi eyodwa kwezingu-{max}}one{Izinkanyezi ezingu-# kwezingu-{max}}other{Izinkanyezi ezingu-# kwezingu-{max}}}"</string>
     <string name="in_progress" msgid="2149208189184319441">"kuyaqhubeka"</string>
     <string name="whichApplication" msgid="5432266899591255759">"Qedela isenzo usebenzisa"</string>
     <string name="whichApplicationNamed" msgid="6969946041713975681">"Qedela isenzo usebenzisa i-%1$s"</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>
@@ -1925,8 +1925,7 @@
     <string name="country_selection_title" msgid="5221495687299014379">"Okuncamelayo kwesifunda"</string>
     <string name="search_language_hint" msgid="7004225294308793583">"Thayipha igama lolimi"</string>
     <string name="language_picker_section_suggested" msgid="6556199184638990447">"Okuphakanyisiwe"</string>
-    <!-- no translation found for language_picker_regions_section_suggested (6080131515268225316) -->
-    <skip />
+    <string name="language_picker_regions_section_suggested" msgid="6080131515268225316">"Okuphakanyisiwe"</string>
     <string name="language_picker_section_suggested_bilingual" msgid="5932198319583556613">"Izilimi eziphakanyisiwe"</string>
     <string name="region_picker_section_suggested_bilingual" msgid="704607569328224133">"Izifunda eziphakanyisiwe"</string>
     <string name="language_picker_section_all" msgid="1985809075777564284">"Zonke izilimi"</string>
@@ -2051,8 +2050,7 @@
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Vumela i-<xliff:g id="LOG_ACCESS_APP_NAME">%s</xliff:g> ukuba ifinyelele wonke amalogu edivayisi?"</string>
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Vumela ukufinyelela kwesikhathi esisodwa"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ungavumeli"</string>
-    <!-- no translation found for log_access_confirmation_body (1806692062668620735) -->
-    <skip />
+    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Amalogu edivayisi arekhoda okwenzekayo kudivayisi yakho. Ama-app angasebenzisa lawa malogu ukuze athole futhi alungise izinkinga.\n\nAmanye amalogu angase aqukathe ulwazi olubucayi, ngakho vumela ama-app owathembayo kuphela ukuthi afinyelele wonke amalogu edivayisi. \n\nUma ungayivumeli le app ukuthi ifinyelele wonke amalogu wedivayisi, isengakwazi ukufinyelela amalogu wayo. Umkhiqizi wedivayisi yakho usengakwazi ukufinyelela amanye amalogu noma ulwazi kudivayisi yakho."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ungabonisi futhi"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"I-<xliff:g id="APP_0">%1$s</xliff:g> ifuna ukubonisa izingcezu ze-<xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Hlela"</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 5fd9dc0..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>
@@ -30,5 +31,4 @@
          lockscreen, setting this to true should come with customized drawables. -->
     <bool name="use_lock_pattern_drawable">false</bool>
     <bool name="resolver_landscape_phone">true</bool>
-    <bool name="system_server_plays_face_haptics">true</bool>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6a52ec9..dfada13 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -935,6 +935,8 @@
         <!-- Nominal White Z --> <item>1.089058</item>
     </string-array>
 
+    <!-- Boolean indicating whether light mode is allowed when DWB is turned on. -->
+    <bool name="config_displayWhiteBalanceLightModeAllowed">true</bool>
 
     <!-- Indicate available ColorDisplayManager.COLOR_MODE_xxx. -->
     <integer-array name="config_availableColorModes">
@@ -1731,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>
@@ -2014,6 +2016,10 @@
     <!-- The default volume for the ring stream -->
     <integer name="config_audio_ring_vol_default">5</integer>
 
+    <!-- The default value for whether head tracking for
+         spatial audio is enabled for a newly connected audio device -->
+    <bool name="config_spatial_audio_head_tracking_enabled_default">false</bool>
+
     <!-- Flag indicating whether platform level volume adjustments are enabled for remote sessions
          on grouped devices. -->
     <bool name="config_volumeAdjustmentForRemoteGroupSessions">true</bool>
@@ -4858,6 +4864,14 @@
         <item>0.875</item>
     </string-array>
 
+    <!-- When each intermediate SFPS enroll stage ends, as a fraction of total progress. -->
+    <string-array name="config_sfps_enroll_stage_thresholds" translatable="false">
+        <item>0</item> <!-- [-1 // <0/25] No animation 1x -->
+        <item>0.36</item> <!-- [0 to 8 // <9/25] Pad center 9x -->
+        <item>0.52</item> <!-- [9 to 12 // <13/25] Tip 4x -->
+        <item>0.76</item> <!-- [13 to 18 // <19/25] Left 6x -->
+    </string-array> <!-- [19 to 24 // <25/25] Right 6x -->
+
     <!-- Messages that should not be shown to the user during face auth enrollment. 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 [email protected] types.hal -->
@@ -5065,6 +5079,10 @@
     <!-- If true, the wallpaper will scale regardless of the value of shouldZoomOutWallpaper() -->
     <bool name="config_alwaysScaleWallpaper">false</bool>
 
+    <!-- Set to true to offset the wallpaper when using multiple displays so that it's centered
+         at the same position as in the largest display.-->
+    <bool name="config_offsetWallpaperToCenterOfLargestDisplay">false</bool>
+
     <!-- Package name that will receive an explicit manifest broadcast for
          android.os.action.POWER_SAVE_MODE_CHANGED. -->
     <string name="config_powerSaveModeChangedListenerPackage" translatable="false"></string>
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 e5b1cf9..63eb83e 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>
@@ -1725,17 +1725,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. Fingerprint sensor disabled.</string>
+    <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 +1797,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] -->
@@ -4525,8 +4525,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 aa0bae6..66bfbb6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -79,6 +79,11 @@
   <java-symbol type="id" name="deny_button" />
   <java-symbol type="id" name="description" />
   <java-symbol type="id" name="divider" />
+  <java-symbol type="id" name="drag" />
+  <java-symbol type="id" name="profile_pager" />
+  <java-symbol type="id" name="chooser_header" />
+  <java-symbol type="id" name="content_preview_container" />
+  <java-symbol type="id" name="profile_tabhost" />
   <java-symbol type="id" name="edit_query" />
   <java-symbol type="id" name="edittext_container" />
   <java-symbol type="id" name="expand_activities_button" />
@@ -282,6 +287,7 @@
   <java-symbol type="integer" name="config_audio_notif_vol_steps" />
   <java-symbol type="integer" name="config_audio_ring_vol_default" />
   <java-symbol type="integer" name="config_audio_ring_vol_steps" />
+  <java-symbol type="bool" name="config_spatial_audio_head_tracking_enabled_default" />
   <java-symbol type="bool" name="config_avoidGfxAccel" />
   <java-symbol type="bool" name="config_bluetooth_address_validation" />
   <java-symbol type="integer" name="config_chooser_max_targets_per_row" />
@@ -1076,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" />
@@ -2701,7 +2707,7 @@
   <java-symbol type="integer" name="config_udfps_illumination_transition_ms" />
   <java-symbol type="bool" name="config_is_powerbutton_fps" />
   <java-symbol type="array" name="config_udfps_enroll_stage_thresholds" />
-
+  <java-symbol type="array" name="config_sfps_enroll_stage_thresholds" />
   <java-symbol type="array" name="config_face_acquire_enroll_ignorelist" />
   <java-symbol type="array" name="config_face_acquire_vendor_enroll_ignorelist" />
   <java-symbol type="array" name="config_face_acquire_keyguard_ignorelist" />
@@ -2824,6 +2830,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" />
@@ -3427,6 +3434,7 @@
   <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" />
   <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" />
+  <java-symbol type="bool" name="config_displayWhiteBalanceLightModeAllowed" />
 
   <!-- Default first user restrictions -->
   <java-symbol type="array" name="config_defaultFirstUserRestrictions" />
@@ -4281,6 +4289,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" />
@@ -4373,6 +4382,10 @@
   <!-- The max scale for the wallpaper when it's zoomed in -->
   <java-symbol type="dimen" name="config_wallpaperMaxScale"/>
 
+  <!-- Set to true to offset the wallpaper when using multiple displays so that it's centered
+        at the same position than in the largest display. -->
+  <java-symbol type="bool" name="config_offsetWallpaperToCenterOfLargestDisplay" />
+
   <!-- Set to true to enable the user switcher on the keyguard. -->
   <java-symbol type="bool" name="config_keyguardUserSwitcher" />
 
@@ -4847,6 +4860,5 @@
 
   <java-symbol type="dimen" name="status_bar_height_default" />
 
-  <java-symbol type="bool" name="system_server_plays_face_haptics" />
   <java-symbol type="string" name="default_card_name"/>
 </resources>
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/AutomaticZenRuleTest.java b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
new file mode 100644
index 0000000..282fdad
--- /dev/null
+++ b/core/tests/coretests/src/android/app/AutomaticZenRuleTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.app;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import android.content.ComponentName;
+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 AutomaticZenRuleTest {
+    private static final String CLASS = "android.app.AutomaticZenRule";
+
+    @Test
+    public void testLongFields_inConstructor() {
+        String longString = Strings.repeat("A", 65536);
+        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+        // test both variants where there's an owner, and where there's a configuration activity
+        AutomaticZenRule rule1 = new AutomaticZenRule(
+                longString, // name
+                new ComponentName("pkg", longString), // owner
+                null,  // configuration activity
+                longUri, // conditionId
+                null, // zen policy
+                0, // interruption filter
+                true); // enabled
+
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                rule1.getConditionId().toString().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule1.getOwner().getClassName().length());
+
+        AutomaticZenRule rule2 = new AutomaticZenRule(
+                longString, // name
+                null, // owner
+                new ComponentName(longString, "SomeClassName"), // configuration activity
+                longUri, // conditionId
+                null, // zen policy
+                0, // interruption filter
+                false); // enabled
+
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule2.getName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                rule2.getConditionId().toString().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                rule2.getConfigurationActivity().getPackageName().length());
+    }
+
+    @Test
+    public void testLongFields_inSetters() {
+        String longString = Strings.repeat("A", 65536);
+        Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+
+        AutomaticZenRule rule = new AutomaticZenRule(
+                "sensible name",
+                new ComponentName("pkg", "ShortClass"),
+                null,
+                Uri.parse("uri://short"),
+                null, 0, true);
+
+        rule.setName(longString);
+        rule.setConditionId(longUri);
+        rule.setConfigurationActivity(new ComponentName(longString, longString));
+
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, rule.getName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                rule.getConditionId().toString().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                rule.getConfigurationActivity().getPackageName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                rule.getConfigurationActivity().getClassName().length());
+    }
+
+    @Test
+    public void testLongInputsFromParcel() {
+        // Create a rule with long fields, set directly via reflection so that we can confirm that
+        // a rule with too-long fields that comes in via a parcel has its fields truncated directly.
+        AutomaticZenRule rule = new AutomaticZenRule(
+                "placeholder",
+                new ComponentName("place", "holder"),
+                null,
+                Uri.parse("uri://placeholder"),
+                null, 0, true);
+
+        try {
+            String longString = Strings.repeat("A", 65536);
+            Uri longUri = Uri.parse("uri://" + Strings.repeat("A", 65530));
+            Field name = Class.forName(CLASS).getDeclaredField("name");
+            name.setAccessible(true);
+            name.set(rule, longString);
+            Field conditionId = Class.forName(CLASS).getDeclaredField("conditionId");
+            conditionId.setAccessible(true);
+            conditionId.set(rule, longUri);
+            Field owner = Class.forName(CLASS).getDeclaredField("owner");
+            owner.setAccessible(true);
+            owner.set(rule, new ComponentName(longString, longString));
+            Field configActivity = Class.forName(CLASS).getDeclaredField("configurationActivity");
+            configActivity.setAccessible(true);
+            configActivity.set(rule, new ComponentName(longString, longString));
+        } catch (NoSuchFieldException e) {
+            fail(e.toString());
+        } catch (ClassNotFoundException e) {
+            fail(e.toString());
+        } catch (IllegalAccessException e) {
+            fail(e.toString());
+        }
+
+        Parcel parcel = Parcel.obtain();
+        rule.writeToParcel(parcel, 0);
+        parcel.setDataPosition(0);
+
+        AutomaticZenRule fromParcel = new AutomaticZenRule(parcel);
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH, fromParcel.getName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                fromParcel.getConditionId().toString().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                fromParcel.getConfigurationActivity().getPackageName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                fromParcel.getConfigurationActivity().getClassName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                fromParcel.getOwner().getPackageName().length());
+        assertEquals(AutomaticZenRule.MAX_STRING_LENGTH,
+                fromParcel.getOwner().getClassName().length());
+    }
+}
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/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/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index 5b3be58..352c6a7 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -39,8 +39,11 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
 
 /** Tests that ensure appropriate settings are backed up. */
 @Presubmit
@@ -710,13 +713,12 @@
 
     @Test
     public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException {
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        final AtomicReference<Properties> changedProperties = new AtomicReference<>();
+        final CompletableFuture<Boolean> completed = new CompletableFuture<>();
 
         DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
-            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-            assertThat(properties.getKeyset()).contains(KEY);
-            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
-            countDownLatch.countDown();
+            changedProperties.set(properties);
+            completed.complete(true);
         };
 
         try {
@@ -724,9 +726,15 @@
                     Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(),
                     changeListener);
             DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
-            assertThat(countDownLatch.await(
+
+            assertThat(completed.get(
                     WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-        } catch (InterruptedException e) {
+
+            Properties properties = changedProperties.get();
+            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+            assertThat(properties.getKeyset()).contains(KEY);
+            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE);
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
             Assert.fail(e.getMessage());
         } finally {
             DeviceConfig.removeOnPropertiesChangedListener(changeListener);
@@ -735,7 +743,6 @@
 
     @Test
     public void onPropertiesChangedListener_setPropertiesCallback() {
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
         DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false);
         DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false);
 
@@ -744,16 +751,12 @@
         keyValues.put(KEY3, VALUE3);
         Properties setProperties = new Properties(NAMESPACE, keyValues);
 
+        final AtomicReference<Properties> changedProperties = new AtomicReference<>();
+        final CompletableFuture<Boolean> completed = new CompletableFuture<>();
+
         DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> {
-            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
-            assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
-            // KEY updated from VALUE to VALUE2
-            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2);
-            // KEY2 deleted (returns default_value)
-            assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value");
-            //KEY3 added with VALUE3
-            assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3);
-            countDownLatch.countDown();
+            changedProperties.set(properties);
+            completed.complete(true);
         };
 
         try {
@@ -761,9 +764,28 @@
                     Objects.requireNonNull(ActivityThread.currentApplication()).getMainExecutor(),
                     changeListener);
             DeviceConfig.setProperties(setProperties);
-            assertThat(countDownLatch.await(
+
+            assertThat(completed.get(
                     WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
-        } catch (InterruptedException | DeviceConfig.BadConfigException e) {
+
+            if (changedProperties.get().getKeyset().size() != 3) {
+                // Sometimes there are a few onChanged callback calls. Let's wait a bit more.
+                final int oneMoreOnChangedDelayMs = 100;
+                Thread.currentThread().sleep(oneMoreOnChangedDelayMs);
+            }
+
+            Properties properties = changedProperties.get();
+            assertThat(properties.getNamespace()).isEqualTo(NAMESPACE);
+            assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3);
+            // KEY updated from VALUE to VALUE2
+            assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2);
+            // KEY2 deleted (returns default_value)
+            assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value");
+            // KEY3 added with VALUE3
+            assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3);
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            Assert.fail(e.getMessage());
+        } catch (DeviceConfig.BadConfigException e) {
             Assert.fail(e.getMessage());
         } finally {
             DeviceConfig.removeOnPropertiesChangedListener(changeListener);
diff --git a/core/tests/coretests/src/android/provider/FontsContractTest.java b/core/tests/coretests/src/android/provider/FontsContractTest.java
index c5d6f7f..21a2205 100644
--- a/core/tests/coretests/src/android/provider/FontsContractTest.java
+++ b/core/tests/coretests/src/android/provider/FontsContractTest.java
@@ -42,6 +42,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -282,9 +283,10 @@
         setupPackageManager();
 
         byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
-        List<byte[]> certList = Arrays.asList(wrongCert);
+        List<byte[]> certList = Collections.singletonList(wrongCert);
         FontRequest requestWrongCerts = new FontRequest(
-                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query",
+                Collections.singletonList(certList));
 
         assertNull(FontsContract.getProvider(mPackageManager, requestWrongCerts));
     }
@@ -293,9 +295,10 @@
             throws PackageManager.NameNotFoundException {
         ProviderInfo info = setupPackageManager();
 
-        List<byte[]> certList = Arrays.asList(BYTE_ARRAY);
+        List<byte[]> certList = Collections.singletonList(BYTE_ARRAY);
         FontRequest requestRightCerts = new FontRequest(
-                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query",
+                Collections.singletonList(certList));
         ProviderInfo result = FontsContract.getProvider(
                 mPackageManager, requestRightCerts);
 
@@ -309,7 +312,8 @@
         byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
         List<byte[]> certList = Arrays.asList(wrongCert, BYTE_ARRAY);
         FontRequest requestRightCerts = new FontRequest(
-                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query",
+                Collections.singletonList(certList));
         assertNull(FontsContract.getProvider(mPackageManager, requestRightCerts));
     }
 
@@ -332,7 +336,8 @@
         // {BYTE_ARRAY_2, BYTE_ARRAY_COPY}.
         List<byte[]> certList = Arrays.asList(BYTE_ARRAY_2, BYTE_ARRAY_COPY);
         FontRequest requestRightCerts = new FontRequest(
-                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", Arrays.asList(certList));
+                TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query",
+                Collections.singletonList(certList));
         assertNull(FontsContract.getProvider(mPackageManager, requestRightCerts));
     }
 
@@ -341,9 +346,9 @@
         ProviderInfo info = setupPackageManager();
 
         List<List<byte[]>> certList = new ArrayList<>();
-        byte[] wrongCert = Base64.decode("this is a wrong cert", Base64.DEFAULT);
-        certList.add(Arrays.asList(wrongCert));
-        certList.add(Arrays.asList(BYTE_ARRAY));
+        certList.add(Collections.singletonList(
+                Base64.decode("this is a wrong cert", Base64.DEFAULT)));
+        certList.add(Collections.singletonList(BYTE_ARRAY));
         FontRequest requestRightCerts = new FontRequest(
                 TestFontsProvider.AUTHORITY, PACKAGE_NAME, "query", certList);
         ProviderInfo result = FontsContract.getProvider(mPackageManager, requestRightCerts);
@@ -356,7 +361,7 @@
         setupPackageManager();
 
         List<List<byte[]>> certList = new ArrayList<>();
-        certList.add(Arrays.asList(BYTE_ARRAY));
+        certList.add(Collections.singletonList(BYTE_ARRAY));
         FontRequest requestRightCerts = new FontRequest(
                 TestFontsProvider.AUTHORITY, "com.wrong.package.name", "query", certList);
         try {
diff --git a/core/tests/coretests/src/android/text/LayoutGetRangeForRectTest.java b/core/tests/coretests/src/android/text/LayoutGetRangeForRectTest.java
new file mode 100644
index 0000000..32fdb5e
--- /dev/null
+++ b/core/tests/coretests/src/android/text/LayoutGetRangeForRectTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.text.method.WordIterator;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class LayoutGetRangeForRectTest {
+
+    private static final int WIDTH = 200;
+    private static final int HEIGHT = 1000;
+    private static final String DEFAULT_TEXT = ""
+            // Line 0 (offset 0 to 18)
+            // - Word 0 (offset 0 to 4) has bounds [0, 40], center 20
+            // - Word 1 (offset 5 to 11) has bounds [50, 110], center 80
+            // - Word 2 (offset 12 to 17) has bounds [120, 170], center 145
+            + "XXXX XXXXXX XXXXX "
+            // Line 1 (offset 18 to 36)
+            // - Word 3 (offset 18 to 23) has bounds [0, 50], center 25
+            // - Word 4 (offset 24 to 26, RTL) has bounds [100, 110], center 105
+            // - Word 5 (offset 27 to 29, RTL) has bounds [80, 90], center 85
+            // - Word 6 start part (offset 30 to 32, RTL) has bounds [60, 70], center 65
+            // - Word 6 end part (offset 32 to 35) has bounds [110, 140], center 125
+            + "XXXXX \u05D1\u05D1 \u05D1\u05D1 \u05D1\u05D1XXX\n"
+            // Line 2 (offset 36 to 38)
+            // - Word 7 start part (offset 36 to 38) has bounds [0, 150], center 75
+            // Line 3 (offset 38 to 40)
+            // - Word 7 middle part (offset 38 to 40) has bounds [0, 150], center 75
+            // Line 4 (offset 40 to 46)
+            // - Word 7 end part (offset 40 to 41) has bounds [0, 100], center 50
+            // - Word 8 (offset 42 to 44) has bounds [110, 130], center 120
+            + "CLCLC XX \n";
+
+    private Layout mLayout;
+    private float[] mLineCenters;
+    private GraphemeClusterSegmentIterator mGraphemeClusterSegmentIterator;
+    private WordSegmentIterator mWordSegmentIterator;
+
+    @Before
+    public void setup() {
+        // The test font includes the following characters:
+        // U+0020 ( ): 10em
+        // U+002E (.): 10em
+        // U+0049 (I): 1em
+        // U+0056 (V): 5em
+        // U+0058 (X): 10em
+        // U+004C (L): 50em
+        // U+0043 (C): 100em
+        // U+005F (_): 0em
+        // U+05D0    : 1em  // HEBREW LETTER ALEF
+        // U+05D1    : 5em  // HEBREW LETTER BET
+        // U+FFFD (invalid surrogate will be replaced to this): 7em
+        // U+10331 (\uD800\uDF31): 10em
+        // Undefined : 0.5em
+        TextPaint textPaint = new TextPaint();
+        textPaint.setTypeface(
+                Typeface.createFromAsset(
+                        InstrumentationRegistry.getInstrumentation().getTargetContext().getAssets(),
+                        "fonts/StaticLayoutLineBreakingTestFont.ttf"));
+        // Make 1 em equal to 1 pixel.
+        textPaint.setTextSize(1.0f);
+
+        mLayout = StaticLayout.Builder.obtain(
+                DEFAULT_TEXT, 0, DEFAULT_TEXT.length(), textPaint, WIDTH).build();
+
+        mLineCenters = new float[mLayout.getLineCount()];
+        for (int i = 0; i < mLayout.getLineCount(); ++i) {
+            mLineCenters[i] = (mLayout.getLineTop(i) + mLayout.getLineBottomWithoutSpacing(i)) / 2f;
+        }
+
+        mGraphemeClusterSegmentIterator =
+                new GraphemeClusterSegmentIterator(DEFAULT_TEXT, textPaint);
+        WordIterator wordIterator = new WordIterator();
+        wordIterator.setCharSequence(DEFAULT_TEXT, 0, DEFAULT_TEXT.length());
+        mWordSegmentIterator = new WordSegmentIterator(DEFAULT_TEXT, wordIterator);
+    }
+
+    @Test
+    public void getRangeForRect_character() {
+        // Character 1 on line 0 has center 15.
+        // Character 2 on line 0 has center 25.
+        RectF area = new RectF(14f, mLineCenters[0] - 1f, 26f, mLineCenters[0] + 1f);
+
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).asList().containsExactly(1, 3).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_partialCharacterButNotCenter() {
+        // Character 0 on line 0 has center 5.
+        // Character 1 on line 0 has center 15.
+        // Character 2 on line 0 has center 25.
+        // Character 3 on line 0 has center 35.
+        RectF area = new RectF(6f, mLineCenters[0] - 1f, 34f, mLineCenters[0] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        // Area partially overlaps characters 0 and 3 but does not contain their centers.
+        assertThat(range).asList().containsExactly(1, 3).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_rtl() {
+        // Character 25 on line 1 has center 102.5.
+        // Character 26 on line 1 has center 95.
+        RectF area = new RectF(94f, mLineCenters[1] - 1f, 103f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).asList().containsExactly(25, 27).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_ltrAndRtl() {
+        // Character 22 on line 1 has center 45.
+        // The end of the RTL run (offset 24 to 32) on line 1 is at 60.
+        RectF area = new RectF(44f, mLineCenters[1] - 1f, 93f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).asList().containsExactly(22, 32).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_rtlAndLtr() {
+        // The start of the RTL run (offset 24 to 32) on line 1 is at 110.
+        // Character 33 on line 1 has center 125.
+        RectF area = new RectF(93f, mLineCenters[1] - 1f, 131f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).asList().containsExactly(24, 34).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_betweenCharacters_shouldFallback() {
+        // Character 1 on line 0 has center 15.
+        // Character 2 on line 0 has center 25.
+        RectF area = new RectF(16f, mLineCenters[0] - 1f, 24f, mLineCenters[0] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).isNull();
+    }
+
+    @Test
+    public void getRangeForRect_character_betweenLines_shouldFallback() {
+        // Area top is below the center of line 0.
+        // Area bottom is above the center of line 1.
+        RectF area = new RectF(0f, mLineCenters[0] + 1f, WIDTH, mLineCenters[1] - 1f);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        // Area partially covers two lines but does not contain the center of any characters.
+        assertThat(range).isNull();
+    }
+
+    @Test
+    public void getRangeForRect_character_multiLine() {
+        // Character 9 on line 0 has center 95.
+        // Character 42 on line 4 has center 115.
+        RectF area = new RectF(93f, 0, 118f, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).asList().containsExactly(9, 43).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_multiLine_betweenCharactersOnSomeLines() {
+        // Character 6 on line 0 has center 65.
+        // Character 7 on line 0 has center 75.
+        // Character 30 on line 1 has center 67.5.
+        // Character 36 on line 2 has center 50.
+        // Character 37 on line 2 has center 125.
+        // Character 38 on line 3 has center 50.
+        // Character 39 on line 3 has center 125.
+        // Character 40 on line 4 has center 50.
+        // Character 41 on line 4 has center 105.
+        RectF area = new RectF(66f, 0, 69f, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        // Area crosses all lines but does not contain the center of any characters on lines 0, 2,
+        // 3, or 4. So the only included character is character 30 on line 1.
+        assertThat(range).asList().containsExactly(30, 31).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_character_multiLine_betweenCharactersOnAllLines_shouldFallback() {
+        // Character 6 on line 0 has center 65.
+        // Character 7 on line 0 has center 75.
+        // Character 30 on line 1 has center 67.5.
+        // Character 31 on line 1 has center 62.5.
+        // Character 36 on line 2 has center 50.
+        // Character 37 on line 2 has center 125.
+        // Character 38 on line 3 has center 50.
+        // Character 39 on line 3 has center 125.
+        // Character 40 on line 4 has center 50.
+        // Character 41 on line 4 has center 105.
+        RectF area = new RectF(66f, 0, 67f, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        // Area crosses all lines but does not contain the center of any characters.
+        assertThat(range).isNull();
+    }
+
+    @Test
+    public void getRangeForRect_character_all() {
+        // Entire area, should include all text.
+        RectF area = new RectF(0f, 0f, WIDTH, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mGraphemeClusterSegmentIterator);
+
+        assertThat(range).asList().containsExactly(0, DEFAULT_TEXT.length()).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word() {
+        // Word 1 (offset 5 to 11) on line 0 has center 80.
+        RectF area = new RectF(79f, mLineCenters[0] - 1f, 81f, mLineCenters[0] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        assertThat(range).asList().containsExactly(5, 11).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_partialWordButNotCenter() {
+        // Word 0 (offset 0 to 4) on line 0 has center 20.
+        // Word 1 (offset 5 to 11) on line 0 has center 80.
+        // Word 2 (offset 12 to 17) on line 0 center 145
+        RectF area = new RectF(21f, mLineCenters[0] - 1f, 144f, mLineCenters[0] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Area partially overlaps words 0 and 2 but does not contain their centers, so only word 1
+        // is included. Whitespace between words is not included.
+        assertThat(range).asList().containsExactly(5, 11).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_rtl() {
+        // Word 4 (offset 24 to 26, RTL) on line 1 center 105
+        RectF area = new RectF(88f, mLineCenters[1] - 1f, 119f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        assertThat(range).asList().containsExactly(24, 26).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_ltrAndRtl() {
+        // Word 3 (offset 18 to 23) on line 1 has center 25
+        // The end of the RTL run (offset 24 to 32) on line 1 is at 60.
+        RectF area = new RectF(24f, mLineCenters[1] - 1f, 93f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Selects all of word 6, not just the first RTL part.
+        assertThat(range).asList().containsExactly(18, 35).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_rtlAndLtr() {
+        // The start of the RTL run (offset 24 to 32) on line 1 is at 110.
+        // End part of word 6 (offset 32 to 35) on line 1 has center 125.
+        RectF area = new RectF(93f, mLineCenters[1] - 1f, 174f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        assertThat(range).asList().containsExactly(24, 35).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_betweenWords_shouldFallback() {
+        // Word 1 on line 0 has center 80.
+        // Word 2 on line 0 has center 145.
+        RectF area = new RectF(81f, mLineCenters[0] - 1f, 144f, mLineCenters[0] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        assertThat(range).isNull();
+    }
+
+    @Test
+    public void getRangeForRect_word_betweenLines_shouldFallback() {
+        // Area top is below the center of line 0.
+        // Area bottom is above the center of line 1.
+        RectF area = new RectF(0f, mLineCenters[0] + 1f, WIDTH, mLineCenters[1] - 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Area partially covers two lines but does not contain the center of any words.
+        assertThat(range).isNull();
+    }
+
+    @Test
+    public void getRangeForRect_word_multiLine() {
+        // Word 1 (offset 5 to 11) on line 0 has center 80.
+        // End part of word 7 (offset 40 to 41) on line 4 has center 50.
+        RectF area = new RectF(42f, 0, 91f, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        assertThat(range).asList().containsExactly(5, 41).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_multiLine_betweenWordsOnSomeLines() {
+        // Word 1 on line 0 has center 80.
+        // Word 2 on line 0 has center 145.
+        // Word 5 (offset 27 to 29) on line 1 has center 85.
+        // Word 7 on line 2 has center 50.
+        // Word 37 on line 2 has center 125.
+        // Word 38 on line 3 has center 50.
+        // Word 39 on line 3 has center 125.
+        // Word 40 on line 4 has center 50.
+        // Word 41 on line 4 has center 105.
+        RectF area = new RectF(84f, 0, 86f, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Area crosses all lines but does not contain the center of any words on lines 0, 2, 3, or
+        // 4. So the only included word is word 5 on line 1.
+        assertThat(range).asList().containsExactly(27, 29).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_multiLine_betweenCharactersOnAllLines_shouldFallback() {
+        // Word 1 on line 0 has center 80.
+        // Word 2 on line 0 has center 145.
+        // Word 4 on line 1 has center 105.
+        // Word 5 on line 1 has center 85.
+        // Word 7 on line 2 has center 50.
+        // Word 37 on line 2 has center 125.
+        // Word 38 on line 3 has center 50.
+        // Word 39 on line 3 has center 125.
+        // Word 40 on line 4 has center 50.
+        // Word 41 on line 4 has center 105.
+        RectF area = new RectF(86f, 0, 89f, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Area crosses all lines but does not contain the center of any words.
+        assertThat(range).isNull();
+    }
+
+    @Test
+    public void getRangeForRect_word_wordSpansMultipleLines_firstPartInsideArea() {
+        // Word 5 (offset 27 to 29) on line 1 has center 85.
+        // First part of word 7 (offset 36 to 38) on line 2 has center 75.
+        RectF area = new RectF(74f, mLineCenters[1] - 1f, 86f, mLineCenters[2] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Selects all of word 7, not just the first part on line 2.
+        assertThat(range).asList().containsExactly(27, 41).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_wordSpansMultipleLines_middlePartInsideArea() {
+        // Middle part of word 7 (offset 38 to 40) on line 2 has center 75.
+        RectF area = new RectF(74f, mLineCenters[3] - 1f, 75f, mLineCenters[3] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Selects all of word 7, not just the middle part on line 3.
+        assertThat(range).asList().containsExactly(36, 41).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_wordSpansMultipleLines_endPartInsideArea() {
+        // End part of word 7 (offset 40 to 41) on line 4 has center 50.
+        // Word 8 (offset 42 to 44) on line 4 has center 120
+        RectF area = new RectF(49f, mLineCenters[4] - 1f, 121f, mLineCenters[4] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Selects all of word 7, not just the middle part on line 3.
+        assertThat(range).asList().containsExactly(36, 44).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_wordSpansMultipleRuns_firstPartInsideArea() {
+        // Word 5 (offset 27 to 29) on line 1 has center 85.
+        // First part of word 6 (offset 30 to 32) on line 1 has center 65.
+        RectF area = new RectF(64f, mLineCenters[1] - 1f, 86f, mLineCenters[1] + 1f);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        // Selects all of word 6, not just the first RTL part.
+        assertThat(range).asList().containsExactly(27, 35).inOrder();
+    }
+
+    @Test
+    public void getRangeForRect_word_all() {
+        // Entire area, should include all text except the last two whitespace characters.
+        RectF area = new RectF(0f, 0f, WIDTH, HEIGHT);
+        int[] range = mLayout.getRangeForRect(area, mWordSegmentIterator);
+
+        assertThat(range).asList().containsExactly(0, DEFAULT_TEXT.length() - 2).inOrder();
+    }
+}
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java b/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java
index 4bea54b..5933d54 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritableViewInfoTest.java
@@ -70,7 +70,8 @@
     @Test
     public void update_viewDisableAutoHandwriting() {
         final Rect rect = new Rect(1, 2, 3, 4);
-        final View view = HandwritingTestUtil.createView(rect, false /* autoHandwritingEnabled */);
+        final View view = HandwritingTestUtil.createView(rect, false /* autoHandwritingEnabled */,
+                true  /* isStylusHandwritingAvailable */);
         final HandwritingInitiator.HandwritableViewInfo handwritableViewInfo =
                 new HandwritingInitiator.HandwritableViewInfo(view);
 
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
index 18da1a4..d4a6632 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingInitiatorTest.java
@@ -16,7 +16,6 @@
 
 package android.view.stylus;
 
-import static android.provider.Settings.Global.STYLUS_HANDWRITING_ENABLED;
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
 import static android.view.MotionEvent.ACTION_UP;
@@ -33,7 +32,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.provider.Settings;
 import android.view.HandwritingInitiator;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -45,15 +43,10 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.PollingCheck;
-
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.concurrent.TimeUnit;
-
 /**
  * Tests for {@link HandwritingInitiator}
  *
@@ -69,8 +62,6 @@
     private static final int HW_BOUNDS_OFFSETS_TOP_PX = 20;
     private static final int HW_BOUNDS_OFFSETS_RIGHT_PX = 30;
     private static final int HW_BOUNDS_OFFSETS_BOTTOM_PX = 40;
-    private static final int SETTING_VALUE_ON = 1;
-    private static final int SETTING_VALUE_OFF = 0;
     private int mHandwritingSlop = 4;
 
     private static final Rect sHwArea = new Rect(100, 200, 500, 500);
@@ -78,29 +69,12 @@
     private HandwritingInitiator mHandwritingInitiator;
     private View mTestView;
     private Context mContext;
-    private int mHwInitialState;
-    private boolean mShouldRestoreInitialHwState;
 
     @Before
     public void setup() throws Exception {
         final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
         mContext = instrumentation.getTargetContext();
 
-        mHwInitialState = Settings.Global.getInt(mContext.getContentResolver(),
-                STYLUS_HANDWRITING_ENABLED, SETTING_VALUE_OFF);
-        if (mHwInitialState != SETTING_VALUE_ON) {
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    STYLUS_HANDWRITING_ENABLED, SETTING_VALUE_ON);
-            mShouldRestoreInitialHwState = true;
-        }
-        String imeId = HandwritingImeService.getImeId();
-        instrumentation.getUiAutomation().executeShellCommand("ime enable " + imeId);
-        instrumentation.getUiAutomation().executeShellCommand("ime set " + imeId);
-        PollingCheck.check("Check that stylus handwriting is available",
-                TimeUnit.SECONDS.toMillis(10),
-                () -> mContext.getSystemService(InputMethodManager.class)
-                        .isStylusHandwritingAvailable());
-
         final ViewConfiguration viewConfiguration = ViewConfiguration.get(mContext);
         mHandwritingSlop = viewConfiguration.getScaledHandwritingSlop();
 
@@ -108,7 +82,8 @@
         mHandwritingInitiator =
                 spy(new HandwritingInitiator(viewConfiguration, inputMethodManager));
 
-        mTestView = createView(sHwArea, true,
+        mTestView = createView(sHwArea, true /* autoHandwritingEnabled */,
+                true /* isStylusHandwritingAvailable */,
                 HW_BOUNDS_OFFSETS_LEFT_PX,
                 HW_BOUNDS_OFFSETS_TOP_PX,
                 HW_BOUNDS_OFFSETS_RIGHT_PX,
@@ -116,17 +91,6 @@
         mHandwritingInitiator.updateHandwritingAreasForView(mTestView);
     }
 
-    @After
-    public void tearDown() throws Exception {
-        if (mShouldRestoreInitialHwState) {
-            mShouldRestoreInitialHwState = false;
-            Settings.Global.putInt(mContext.getContentResolver(),
-                    STYLUS_HANDWRITING_ENABLED, mHwInitialState);
-        }
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                .executeShellCommand("ime reset");
-    }
-
     @Test
     public void onTouchEvent_startHandwriting_when_stylusMoveOnce_withinHWArea() {
         mHandwritingInitiator.onInputConnectionCreated(mTestView);
@@ -244,17 +208,15 @@
     }
 
     @Test
-    public void onTouchEvent_notStartHandwriting_whenHandwritingNotAvailable() throws Exception {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation()
-                .executeShellCommand("ime reset");
-        PollingCheck.check("Check that stylus handwriting is unavailable",
-                TimeUnit.SECONDS.toMillis(10),
-                () -> !mContext.getSystemService(InputMethodManager.class)
-                        .isStylusHandwritingAvailable());
+    public void onTouchEvent_notStartHandwriting_whenHandwritingNotAvailable() {
+        final Rect rect = new Rect(600, 600, 900, 900);
+        final View testView = createView(rect, true /* autoHandwritingEnabled */,
+                false /* isStylusHandwritingAvailable */);
+        mHandwritingInitiator.updateHandwritingAreasForView(testView);
 
-        mHandwritingInitiator.onInputConnectionCreated(mTestView);
-        final int x1 = (sHwArea.left + sHwArea.right) / 2;
-        final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
+        mHandwritingInitiator.onInputConnectionCreated(testView);
+        final int x1 = (rect.left + rect.right) / 2;
+        final int y1 = (rect.top + rect.bottom) / 2;
         MotionEvent stylusEvent1 = createStylusEvent(ACTION_DOWN, x1, y1, 0);
         mHandwritingInitiator.onTouchEvent(stylusEvent1);
 
@@ -356,7 +318,8 @@
 
     @Test
     public void autoHandwriting_whenDisabled_wontStartHW() {
-        View mockView = createView(sHwArea, false);
+        View mockView = createView(sHwArea, false /* autoHandwritingEnabled */,
+                true /* isStylusHandwritingAvailable */);
         mHandwritingInitiator.onInputConnectionCreated(mockView);
         final int x1 = (sHwArea.left + sHwArea.right) / 2;
         final int y1 = (sHwArea.top + sHwArea.bottom) / 2;
diff --git a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
index e6e50e9..388a996 100644
--- a/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
+++ b/core/tests/coretests/src/android/view/stylus/HandwritingTestUtil.java
@@ -29,14 +29,18 @@
 
 public class HandwritingTestUtil {
     public static View createView(Rect handwritingArea) {
-        return createView(handwritingArea, true);
-    }
-
-    public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled) {
-        return createView(handwritingArea, autoHandwritingEnabled, 0, 0, 0, 0);
+        return createView(handwritingArea, true /* autoHandwritingEnabled */,
+                true /* isStylusHandwritingAvailable */);
     }
 
     public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
+            boolean isStylusHandwritingAvailable) {
+        return createView(handwritingArea, autoHandwritingEnabled, isStylusHandwritingAvailable,
+                0, 0, 0, 0);
+    }
+
+    public static View createView(Rect handwritingArea, boolean autoHandwritingEnabled,
+            boolean isStylusHandwritingAvailable,
             float handwritingBoundsOffsetLeft, float handwritingBoundsOffsetTop,
             float handwritingBoundsOffsetRight, float handwritingBoundsOffsetBottom) {
         final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
@@ -57,6 +61,7 @@
         View view = spy(new View(context));
         when(view.isAttachedToWindow()).thenReturn(true);
         when(view.isAggregatedVisible()).thenReturn(true);
+        when(view.isStylusHandwritingAvailable()).thenReturn(isStylusHandwritingAvailable);
         when(view.getHandwritingArea()).thenReturn(handwritingArea);
         when(view.getHandwritingBoundsOffsetLeft()).thenReturn(handwritingBoundsOffsetLeft);
         when(view.getHandwritingBoundsOffsetTop()).thenReturn(handwritingBoundsOffsetTop);
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/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/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
index 0cee526..271a20b 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LocalImageResolverTest.java
@@ -17,6 +17,8 @@
 package com.android.internal.widget;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.BitmapDrawable;
@@ -279,4 +281,49 @@
         // This drawable must not be loaded - if it was, the code ignored the package specification.
         assertThat(d).isNull();
     }
+
+    @Test
+    public void resolveResourcesForIcon_notAResourceIcon_returnsNull() {
+        Icon icon = Icon.createWithContentUri(Uri.parse("some_uri"));
+        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull();
+    }
+
+    @Test
+    public void resolveResourcesForIcon_localPackageIcon_returnsPackageResources() {
+        Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24);
+        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon))
+                .isSameInstanceAs(mContext.getResources());
+    }
+
+    @Test
+    public void resolveResourcesForIcon_iconWithoutPackageSpecificed_returnsPackageResources() {
+        Icon icon = Icon.createWithResource("", R.drawable.test32x24);
+        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon))
+                .isSameInstanceAs(mContext.getResources());
+    }
+
+    @Test
+    public void resolveResourcesForIcon_systemPackageSpecified_returnsSystemPackage() {
+        Icon icon = Icon.createWithResource("android", R.drawable.test32x24);
+        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isSameInstanceAs(
+                Resources.getSystem());
+    }
+
+    @Test
+    public void resolveResourcesForIcon_differentPackageSpecified_returnsPackageResources() throws
+            PackageManager.NameNotFoundException {
+        String pkg = "com.android.settings";
+        Resources res = mContext.getPackageManager().getResourcesForApplication(pkg);
+        int resId = res.getIdentifier("ic_android", "drawable", pkg);
+        Icon icon = Icon.createWithResource(pkg, resId);
+
+        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon).getDrawable(resId,
+                mContext.getTheme())).isNotNull();
+    }
+
+    @Test
+    public void resolveResourcesForIcon_invalidPackageSpecified_returnsNull() {
+        Icon icon = Icon.createWithResource("invalid.package", R.drawable.test32x24);
+        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull();
+    }
 }
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index f030d80..e0e13f5 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -81,5 +81,6 @@
         <permission name="android.permission.READ_DEVICE_CONFIG" />
         <permission name="android.permission.READ_SAFETY_CENTER_STATUS" />
         <permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
+        <permission name="android.permission.READ_SEARCH_INDEXABLES" />
     </privapp-permissions>
 </permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 3170177..682483d9 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1,12 +1,6 @@
 {
   "version": "1.0.0",
   "messages": {
-    "-2146181682": {
-      "message": "Releasing screen wakelock, obscured by %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
     "-2127842445": {
       "message": "Clearing startingData for token=%s",
       "level": "VERBOSE",
@@ -1783,6 +1777,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "-384639879": {
+      "message": "Acquiring screen wakelock due to %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "-381522987": {
       "message": "Display %d state is now (%d), so update recording?",
       "level": "VERBOSE",
@@ -1825,6 +1825,12 @@
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
+    "-353495930": {
+      "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
     "-347866078": {
       "message": "Setting move animation on %s",
       "level": "VERBOSE",
@@ -2389,6 +2395,12 @@
       "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
+    "191486492": {
+      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "200829729": {
       "message": "ScreenRotationAnimation onAnimationEnd",
       "level": "DEBUG",
@@ -2509,6 +2521,12 @@
       "group": "WM_DEBUG_ANIM",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "286170861": {
+      "message": "Creating Pending Transition for TaskFragment: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
     "288485303": {
       "message": "Attempted to set remove mode to a display that does not exist: %d",
       "level": "WARN",
@@ -3055,6 +3073,12 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
+    "782864973": {
+      "message": "Releasing screen wakelock, obscured by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
     "791468751": {
       "message": "Pausing rotation during re-position",
       "level": "DEBUG",
@@ -3193,12 +3217,6 @@
       "group": "WM_DEBUG_LOCKTASK",
       "at": "com\/android\/server\/wm\/LockTaskController.java"
     },
-    "956467125": {
-      "message": "Reparenting Activity to embedded TaskFragment, but the Activity is not collected",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
     "958338552": {
       "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
       "level": "VERBOSE",
@@ -4303,18 +4321,6 @@
       "group": "WM_ERROR",
       "at": "com\/android\/server\/wm\/WindowManagerService.java"
     },
-    "2088592090": {
-      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "2096635066": {
-      "message": "Acquiring screen wakelock due to %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
     "2100457473": {
       "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.",
       "level": "DEBUG",
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index c117816..a186aca 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
@@ -415,6 +418,9 @@
 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
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 582488f..ca3c847 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -2796,7 +2796,8 @@
                 if (mWhitePoint == null || mTransform == null) {
                     throw new IllegalStateException(
                             "ColorSpace (" + this + ") cannot create native object! mWhitePoint: "
-                            + mWhitePoint + " mTransform: " + mTransform);
+                            + Arrays.toString(mWhitePoint) + " mTransform: "
+                            + Arrays.toString(mTransform));
                 }
 
                 // This mimics the old code that was in native.
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/ktfmt_includes.txt b/ktfmt_includes.txt
deleted file mode 100644
index c7062e0..0000000
--- a/ktfmt_includes.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-packages/SystemUI/compose/
-packages/SystemUI/screenshot/
-packages/SystemUI/src/com/android/systemui/people/data
-packages/SystemUI/src/com/android/systemui/people/ui
-packages/SystemUI/src/com/android/systemui/keyguard/data
-packages/SystemUI/src/com/android/systemui/keyguard/dagger
-packages/SystemUI/src/com/android/systemui/keyguard/domain
-packages/SystemUI/src/com/android/systemui/keyguard/shared
-packages/SystemUI/src/com/android/systemui/keyguard/ui
-packages/SystemUI/src/com/android/systemui/qs/footer
-packages/SystemUI/src/com/android/systemui/security
-packages/SystemUI/src/com/android/systemui/common/
-packages/SystemUI/tests/utils/src/com/android/systemui/qs/
-packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeSecurityController.kt
-packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeUserInfoController.kt
-packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/MockUserSwitcherControllerWrapper.kt
-packages/SystemUI/tests/src/com/android/systemui/qs/footer/
\ No newline at end of file
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 02af916..6af3d2b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -22,6 +22,7 @@
 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_TASK_FRAGMENT_INFO;
 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
+import static android.window.TaskFragmentOrganizer.getTransitionType;
 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;
@@ -109,7 +110,7 @@
     private Consumer<List<SplitInfo>> mEmbeddingCallback;
     private final List<SplitInfo> mLastReportedSplitStates = new ArrayList<>();
     private final Handler mHandler;
-    private final Object mLock = new Object();
+    final Object mLock = new Object();
     private final ActivityStartMonitor mActivityStartMonitor;
 
     public SplitController() {
@@ -209,8 +210,10 @@
                 }
             }
 
-            // Notify the server, and the server should apply the WindowContainerTransaction.
-            mPresenter.onTransactionHandled(transaction.getTransactionToken(), wct);
+            // Notify the server, and the server should apply and merge the
+            // WindowContainerTransaction to the active sync to finish the TaskFragmentTransaction.
+            mPresenter.onTransactionHandled(transaction.getTransactionToken(), wct,
+                    getTransitionType(wct), false /* shouldApplyIndependently */);
             updateCallbackIfNecessary();
         }
     }
@@ -221,6 +224,9 @@
      * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed.
      * @param taskFragmentInfo  Info of the TaskFragment that is created.
      */
+    // Suppress GuardedBy warning because lint ask to mark this method as
+    // @GuardedBy(container.mController.mLock), which is mLock itself
+    @SuppressWarnings("GuardedBy")
     @VisibleForTesting
     @GuardedBy("mLock")
     void onTaskFragmentAppeared(@NonNull WindowContainerTransaction wct,
@@ -245,6 +251,9 @@
      * @param wct   The {@link WindowContainerTransaction} to make any changes with if needed.
      * @param taskFragmentInfo  Info of the TaskFragment that is changed.
      */
+    // Suppress GuardedBy warning because lint ask to mark this method as
+    // @GuardedBy(container.mController.mLock), which is mLock itself
+    @SuppressWarnings("GuardedBy")
     @VisibleForTesting
     @GuardedBy("mLock")
     void onTaskFragmentInfoChanged(@NonNull WindowContainerTransaction wct,
@@ -430,6 +439,9 @@
      *                          transaction operation.
      * @param exception             exception from the server side.
      */
+    // Suppress GuardedBy warning because lint ask to mark this method as
+    // @GuardedBy(container.mController.mLock), which is mLock itself
+    @SuppressWarnings("GuardedBy")
     @VisibleForTesting
     @GuardedBy("mLock")
     void onTaskFragmentError(@NonNull WindowContainerTransaction wct,
@@ -571,7 +583,7 @@
         }
 
         if (!isOnReparent && getContainerWithActivity(activity) == null
-                && getInitialTaskFragmentToken(activity) != null) {
+                && getTaskFragmentTokenFromActivityClientRecord(activity) != null) {
             // We can't find the new launched activity in any recorded container, but it is
             // currently placed in an embedded TaskFragment. This can happen in two cases:
             // 1. the activity is embedded in another app.
@@ -792,6 +804,9 @@
      * Checks if there is a rule to split the two activities. If there is one, puts them into split
      * and returns {@code true}. Otherwise, returns {@code false}.
      */
+    // Suppress GuardedBy warning because lint ask to mark this method as
+    // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
+    @SuppressWarnings("GuardedBy")
     @GuardedBy("mLock")
     private boolean putActivitiesIntoSplitIfNecessary(@NonNull WindowContainerTransaction wct,
             @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity) {
@@ -851,11 +866,12 @@
     }
 
     @VisibleForTesting
+    @GuardedBy("mLock")
     void onActivityDestroyed(@NonNull Activity activity) {
         // Remove any pending appeared activity, as the server won't send finished activity to the
         // organizer.
         for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
-            mTaskContainers.valueAt(i).cleanupPendingAppearedActivity(activity);
+            mTaskContainers.valueAt(i).onActivityDestroyed(activity);
         }
         // We didn't trigger the callback if there were any pending appeared activities, so check
         // again after the pending is removed.
@@ -866,23 +882,53 @@
      * Called when we have been waiting too long for the TaskFragment to become non-empty after
      * creation.
      */
+    @GuardedBy("mLock")
     void onTaskFragmentAppearEmptyTimeout(@NonNull TaskFragmentContainer container) {
-        synchronized (mLock) {
-            final WindowContainerTransaction wct = new WindowContainerTransaction();
-            onTaskFragmentAppearEmptyTimeout(wct, container);
-            mPresenter.applyTransaction(wct);
-        }
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        onTaskFragmentAppearEmptyTimeout(wct, container);
+        // Can be applied independently as a timeout callback.
+        mPresenter.applyTransaction(wct, getTransitionType(wct),
+                true /* shouldApplyIndependently */);
     }
 
     /**
      * Called when we have been waiting too long for the TaskFragment to become non-empty after
      * creation.
      */
+    @GuardedBy("mLock")
     void onTaskFragmentAppearEmptyTimeout(@NonNull WindowContainerTransaction wct,
             @NonNull TaskFragmentContainer container) {
-        synchronized (mLock) {
-            mPresenter.cleanupContainer(wct, container, false /* shouldFinishDependent */);
+        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 */);
     }
 
     /**
@@ -1590,15 +1636,16 @@
     }
 
     /**
-     * Gets the token of the initial TaskFragment that embedded this activity. Do not rely on it
-     * after creation because the activity could be reparented.
+     * Gets the token of the TaskFragment that embedded this activity. It is available as soon as
+     * the activity is created and attached, so it can be used during {@link #onActivityCreated}
+     * before the server notifies the organizer to avoid racing condition.
      */
     @VisibleForTesting
     @Nullable
-    IBinder getInitialTaskFragmentToken(@NonNull Activity activity) {
+    IBinder getTaskFragmentTokenFromActivityClientRecord(@NonNull Activity activity) {
         final ActivityThread.ActivityClientRecord record = ActivityThread.currentActivityThread()
                 .getActivityClient(activity.getActivityToken());
-        return record != null ? record.mInitialTaskFragmentToken : null;
+        return record != null ? record.mTaskFragmentToken : null;
     }
 
     /**
@@ -1676,7 +1723,8 @@
                 @Nullable Bundle savedInstanceState) {
             synchronized (mLock) {
                 final IBinder activityToken = activity.getActivityToken();
-                final IBinder initialTaskFragmentToken = getInitialTaskFragmentToken(activity);
+                final IBinder initialTaskFragmentToken =
+                        getTaskFragmentTokenFromActivityClientRecord(activity);
                 // If the activity is not embedded, then it will not have an initial task fragment
                 // token so no further action is needed.
                 if (initialTaskFragmentToken == null) {
@@ -1711,7 +1759,9 @@
             synchronized (mLock) {
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
                 SplitController.this.onActivityCreated(wct, activity);
-                mPresenter.applyTransaction(wct);
+                // The WCT should be applied and merged to the activity launch transition.
+                mPresenter.applyTransaction(wct, getTransitionType(wct),
+                        false /* shouldApplyIndependently */);
             }
         }
 
@@ -1720,7 +1770,10 @@
             synchronized (mLock) {
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
                 SplitController.this.onActivityConfigurationChanged(wct, activity);
-                mPresenter.applyTransaction(wct);
+                // The WCT should be applied and merged to the Task change transition so that the
+                // placeholder is launched in the same transition.
+                mPresenter.applyTransaction(wct, getTransitionType(wct),
+                        false /* shouldApplyIndependently */);
             }
         }
 
@@ -1754,25 +1807,43 @@
         @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) {
-                    mPresenter.applyTransaction(wct);
+                    // Make sure the WCT is applied immediately instead of being queued so that the
+                    // TaskFragment will be ready before activity attachment.
+                    mPresenter.applyTransaction(wct, getTransitionType(wct),
+                            false /* shouldApplyIndependently */);
                     // Amend the request to let the WM know that the activity should be placed in
                     // the dedicated container.
                     options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 2b069d7..2ef8e4c 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -38,6 +38,7 @@
 import android.view.WindowMetrics;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -171,6 +172,7 @@
      *                          created and the activity will be re-parented to it.
      * @param rule The split rule to be applied to the container.
      */
+    @GuardedBy("mController.mLock")
     void createNewSplitContainer(@NonNull WindowContainerTransaction wct,
             @NonNull Activity primaryActivity, @NonNull Activity secondaryActivity,
             @NonNull SplitPairRule rule) {
@@ -187,8 +189,10 @@
         final TaskFragmentContainer curSecondaryContainer = mController.getContainerWithActivity(
                 secondaryActivity);
         TaskFragmentContainer containerToAvoid = primaryContainer;
-        if (rule.shouldClearTop() && curSecondaryContainer != null) {
-            // Do not reuse the current TaskFragment if the rule is to clear top.
+        if (curSecondaryContainer != null
+                && (rule.shouldClearTop() || primaryContainer.isAbove(curSecondaryContainer))) {
+            // Do not reuse the current TaskFragment if the rule is to clear top, or if it is below
+            // the primary TaskFragment.
             containerToAvoid = curSecondaryContainer;
         }
         final TaskFragmentContainer secondaryContainer = prepareContainerForActivity(wct,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 77e26c0..b563677 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -137,6 +137,13 @@
         return mContainers.isEmpty() && mFinishedContainer.isEmpty();
     }
 
+    /** Called when the activity is destroyed. */
+    void onActivityDestroyed(@NonNull Activity activity) {
+        for (TaskFragmentContainer container : mContainers) {
+            container.onActivityDestroyed(activity);
+        }
+    }
+
     /** Removes the pending appeared activity from all TaskFragments in this Task. */
     void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
         for (TaskFragmentContainer container : mContainers) {
@@ -162,4 +169,8 @@
         }
         return null;
     }
+
+    int indexOf(@NonNull TaskFragmentContainer child) {
+        return mContainers.indexOf(child);
+    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 11c0db3..626e0d9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.app.Activity;
+import android.app.ActivityThread;
 import android.app.WindowConfiguration.WindowingMode;
 import android.content.Intent;
 import android.graphics.Rect;
@@ -28,6 +29,7 @@
 import android.window.TaskFragmentInfo;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -189,6 +191,19 @@
         // Remove the pending activity from other TaskFragments.
         mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity);
         mPendingAppearedActivities.add(pendingAppearedActivity);
+        updateActivityClientRecordTaskFragmentToken(pendingAppearedActivity);
+    }
+
+    /**
+     * Updates the {@link ActivityThread.ActivityClientRecord#mTaskFragmentToken} for the
+     * activity. This makes sure the token is up-to-date if the activity is relaunched later.
+     */
+    private void updateActivityClientRecordTaskFragmentToken(@NonNull Activity activity) {
+        final ActivityThread.ActivityClientRecord record = ActivityThread
+                .currentActivityThread().getActivityClient(activity.getActivityToken());
+        if (record != null) {
+            record.mTaskFragmentToken = mToken;
+        }
     }
 
     void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
@@ -196,8 +211,29 @@
     }
 
     void clearPendingAppearedActivities() {
+        final List<Activity> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
+        // Clear mPendingAppearedActivities so that #getContainerWithActivity won't return the
+        // current TaskFragment.
         mPendingAppearedActivities.clear();
         mPendingAppearedIntent = null;
+
+        // For removed pending activities, we need to update the them to their previous containers.
+        for (Activity activity : cleanupActivities) {
+            final TaskFragmentContainer curContainer = mController.getContainerWithActivity(
+                    activity);
+            if (curContainer != null) {
+                curContainer.updateActivityClientRecordTaskFragmentToken(activity);
+            }
+        }
+    }
+
+    /** Called when the activity is destroyed. */
+    void onActivityDestroyed(@NonNull Activity activity) {
+        removePendingAppearedActivity(activity);
+        if (mInfo != null) {
+            // Remove the activity now because there can be a delay before the server callback.
+            mInfo.getActivities().remove(activity.getActivityToken());
+        }
     }
 
     @Nullable
@@ -251,6 +287,7 @@
         return mInfo;
     }
 
+    @GuardedBy("mController.mLock")
     void setInfo(@NonNull WindowContainerTransaction wct, @NonNull TaskFragmentInfo info) {
         if (!mIsFinished && mInfo == null && info.isEmpty()) {
             // onTaskFragmentAppeared with empty info. We will remove the TaskFragment if no
@@ -258,10 +295,12 @@
             // it is still empty after timeout.
             if (mPendingAppearedIntent != null || !mPendingAppearedActivities.isEmpty()) {
                 mAppearEmptyTimeout = () -> {
-                    mAppearEmptyTimeout = null;
-                    // Call without the pass-in wct when timeout. We need to applyWct directly
-                    // in this case.
-                    mController.onTaskFragmentAppearEmptyTimeout(this);
+                    synchronized (mController.mLock) {
+                        mAppearEmptyTimeout = null;
+                        // Call without the pass-in wct when timeout. We need to applyWct directly
+                        // in this case.
+                        mController.onTaskFragmentAppearEmptyTimeout(this);
+                    }
                 };
                 mController.getHandler().postDelayed(mAppearEmptyTimeout, APPEAR_EMPTY_TIMEOUT_MS);
             } else {
@@ -501,6 +540,18 @@
         return new Size(maxMinWidth, maxMinHeight);
     }
 
+    /** Whether the current TaskFragment is above the {@code other} TaskFragment. */
+    boolean isAbove(@NonNull TaskFragmentContainer other) {
+        if (mTaskContainer != other.mTaskContainer) {
+            throw new IllegalArgumentException(
+                    "Trying to compare two TaskFragments in different Task.");
+        }
+        if (this == other) {
+            throw new IllegalArgumentException("Trying to compare a TaskFragment with itself.");
+        }
+        return mTaskContainer.indexOf(this) > mTaskContainer.indexOf(other);
+    }
+
     @Override
     public String toString() {
         return toString(true /* includeContainersToFinishOnExit */);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
index d0eaf34..58a627b 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/JetpackTaskFragmentOrganizerTest.java
@@ -20,7 +20,6 @@
 
 import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_ID;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
@@ -33,7 +32,6 @@
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Point;
-import android.os.Handler;
 import android.platform.test.annotations.Presubmit;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentTransaction;
@@ -67,10 +65,7 @@
     private WindowContainerTransaction mTransaction;
     @Mock
     private JetpackTaskFragmentOrganizer.TaskFragmentCallback mCallback;
-    @Mock
     private SplitController mSplitController;
-    @Mock
-    private Handler mHandler;
     private JetpackTaskFragmentOrganizer mOrganizer;
 
     @Before
@@ -78,8 +73,9 @@
         MockitoAnnotations.initMocks(this);
         mOrganizer = new JetpackTaskFragmentOrganizer(Runnable::run, mCallback);
         mOrganizer.registerOrganizer();
+        mSplitController = new SplitController();
         spyOn(mOrganizer);
-        doReturn(mHandler).when(mSplitController).getHandler();
+        spyOn(mSplitController);
     }
 
     @Test
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index f743610..58870a6 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -127,7 +127,7 @@
         mSplitPresenter = mSplitController.mPresenter;
         spyOn(mSplitController);
         spyOn(mSplitPresenter);
-        doNothing().when(mSplitPresenter).applyTransaction(any());
+        doNothing().when(mSplitPresenter).applyTransaction(any(), anyInt(), anyBoolean());
         final Configuration activityConfig = new Configuration();
         activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
         activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
@@ -930,7 +930,8 @@
 
     @Test
     public void testResolveActivityToContainer_inUnknownTaskFragment() {
-        doReturn(new Binder()).when(mSplitController).getInitialTaskFragmentToken(mActivity);
+        doReturn(new Binder()).when(mSplitController)
+                .getTaskFragmentTokenFromActivityClientRecord(mActivity);
 
         // No need to handle when the new launched activity is in an unknown TaskFragment.
         assertTrue(mSplitController.resolveActivityToContainer(mTransaction, mActivity,
@@ -1000,7 +1001,8 @@
         mSplitController.onTransactionReady(transaction);
 
         verify(mSplitController).onTaskFragmentAppeared(any(), eq(info));
-        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
+        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
     }
 
     @Test
@@ -1014,7 +1016,8 @@
         mSplitController.onTransactionReady(transaction);
 
         verify(mSplitController).onTaskFragmentInfoChanged(any(), eq(info));
-        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
+        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
     }
 
     @Test
@@ -1028,7 +1031,8 @@
         mSplitController.onTransactionReady(transaction);
 
         verify(mSplitController).onTaskFragmentVanished(any(), eq(info));
-        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
+        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
     }
 
     @Test
@@ -1043,7 +1047,8 @@
 
         verify(mSplitController).onTaskFragmentParentInfoChanged(any(), eq(TASK_ID),
                 eq(taskConfig));
-        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
+        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
     }
 
     @Test
@@ -1062,7 +1067,8 @@
 
         verify(mSplitController).onTaskFragmentError(any(), eq(errorToken), eq(info), eq(opType),
                 eq(exception));
-        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
+        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
     }
 
     @Test
@@ -1078,7 +1084,8 @@
 
         verify(mSplitController).onActivityReparentedToTask(any(), eq(TASK_ID), eq(intent),
                 eq(activityToken));
-        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any());
+        verify(mSplitPresenter).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
     }
 
     /** Creates a mock activity in the organizer process. */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
index da724d9..25f0e25 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitPresenterTest.java
@@ -39,6 +39,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -247,6 +248,26 @@
         verify(mPresenter).expandTaskFragment(mTransaction, secondaryTf.getTaskFragmentToken());
     }
 
+    @Test
+    public void testCreateNewSplitContainer_secondaryAbovePrimary() {
+        final Activity secondaryActivity = createMockActivity();
+        final TaskFragmentContainer bottomTf = mController.newContainer(secondaryActivity, TASK_ID);
+        final TaskFragmentContainer primaryTf = mController.newContainer(mActivity, TASK_ID);
+        final SplitPairRule rule = new SplitPairRule.Builder(pair ->
+                pair.first == mActivity && pair.second == secondaryActivity, pair -> false,
+                metrics -> true)
+                .setShouldClearTop(false)
+                .build();
+
+        mPresenter.createNewSplitContainer(mTransaction, mActivity, secondaryActivity, rule);
+
+        assertEquals(primaryTf, mController.getContainerWithActivity(mActivity));
+        final TaskFragmentContainer secondaryTf = mController.getContainerWithActivity(
+                secondaryActivity);
+        assertNotEquals(bottomTf, secondaryTf);
+        assertTrue(secondaryTf.isAbove(primaryTf));
+    }
+
     private Activity createMockActivity() {
         final Activity activity = mock(Activity.class);
         final Configuration activityConfig = new Configuration();
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index 6cbecff..082774e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -288,6 +288,18 @@
     }
 
     @Test
+    public void testIsAbove() {
+        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+        final TaskFragmentContainer container0 = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+        final TaskFragmentContainer container1 = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+
+        assertTrue(container1.isAbove(container0));
+        assertFalse(container0.isAbove(container1));
+    }
+
+    @Test
     public void testGetBottomMostActivity() {
         final TaskContainer taskContainer = new TaskContainer(TASK_ID);
         final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
@@ -304,6 +316,25 @@
         assertEquals(activity, container.getBottomMostActivity());
     }
 
+    @Test
+    public void testOnActivityDestroyed() {
+        final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+        final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+        container.addPendingAppearedActivity(mActivity);
+        final List<IBinder> activities = new ArrayList<>();
+        activities.add(mActivity.getActivityToken());
+        doReturn(activities).when(mInfo).getActivities();
+        container.setInfo(mTransaction, mInfo);
+
+        assertTrue(container.hasActivity(mActivity.getActivityToken()));
+
+        taskContainer.onActivityDestroyed(mActivity);
+
+        // It should not contain the destroyed Activity.
+        assertFalse(container.hasActivity(mActivity.getActivityToken()));
+    }
+
     /** Creates a mock activity in the organizer process. */
     private Activity createMockActivity() {
         final Activity activity = mock(Activity.class);
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_letterboxed_app.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_letterboxed_app.xml
deleted file mode 100644
index 6fcd1de..0000000
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_letterboxed_app.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/letterbox_education_dialog_icon_size"
-        android:height="@dimen/letterbox_education_dialog_icon_size"
-        android:viewportWidth="48"
-        android:viewportHeight="48">
-    <path
-        android:fillColor="@color/letterbox_education_accent_primary"
-        android:fillType="evenOdd"
-        android:pathData="M2 8C0.895431 8 0 8.89543 0 10V38C0 39.1046 0.895431 40 2 40H46C47.1046 40 48 39.1046 48 38V10C48 8.89543 47.1046 8 46 8H2ZM44 12H4V36H44V12Z" />
-    <path
-        android:fillColor="@color/letterbox_education_accent_primary"
-        android:pathData="M 17 14 L 31 14 Q 32 14 32 15 L 32 33 Q 32 34 31 34 L 17 34 Q 16 34 16 33 L 16 15 Q 16 14 17 14 Z" />
-</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml
new file mode 100644
index 0000000..ddfb5c2
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_light_bulb.xml
@@ -0,0 +1,26 @@
+<?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.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="@dimen/letterbox_education_dialog_title_icon_width"
+        android:height="@dimen/letterbox_education_dialog_title_icon_height"
+        android:viewportWidth="45"
+        android:viewportHeight="44">
+
+    <path
+        android:fillColor="@color/letterbox_education_accent_primary"
+        android:pathData="M11 40H19C19 42.2 17.2 44 15 44C12.8 44 11 42.2 11 40ZM7 38L23 38V34L7 34L7 38ZM30 19C30 26.64 24.68 30.72 22.46 32L7.54 32C5.32 30.72 0 26.64 0 19C0 10.72 6.72 4 15 4C23.28 4 30 10.72 30 19ZM26 19C26 12.94 21.06 8 15 8C8.94 8 4 12.94 4 19C4 23.94 6.98 26.78 8.7 28L21.3 28C23.02 26.78 26 23.94 26 19ZM39.74 14.74L37 16L39.74 17.26L41 20L42.26 17.26L45 16L42.26 14.74L41 12L39.74 14.74ZM35 12L36.88 7.88L41 6L36.88 4.12L35 0L33.12 4.12L29 6L33.12 7.88L35 12Z" />
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml
index cbfcfd0..22a8f39 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_reposition.xml
@@ -15,18 +15,16 @@
   ~ limitations under the License.
   -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/letterbox_education_dialog_icon_size"
-        android:height="@dimen/letterbox_education_dialog_icon_size"
-        android:viewportWidth="48"
-        android:viewportHeight="48">
+        android:width="@dimen/letterbox_education_dialog_icon_width"
+        android:height="@dimen/letterbox_education_dialog_icon_height"
+        android:viewportWidth="40"
+        android:viewportHeight="32">
+
     <path
         android:fillColor="@color/letterbox_education_text_secondary"
         android:fillType="evenOdd"
-        android:pathData="M2 8C0.895431 8 0 8.89543 0 10V38C0 39.1046 0.895431 40 2 40H46C47.1046 40 48 39.1046 48 38V10C48 8.89543 47.1046 8 46 8H2ZM44 12H4V36H44V12Z" />
+        android:pathData="M4 0C1.79086 0 0 1.79086 0 4V28C0 30.2091 1.79086 32 4 32H36C38.2091 32 40 30.2091 40 28V4C40 1.79086 38.2091 0 36 0H4ZM36 4H4V28H36V4Z" />
     <path
         android:fillColor="@color/letterbox_education_text_secondary"
-        android:pathData="M 14 22 H 30 V 26 H 14 V 22 Z" />
-    <path
-        android:fillColor="@color/letterbox_education_text_secondary"
-        android:pathData="M26 16L34 24L26 32V16Z" />
+        android:pathData="M19.98 8L17.16 10.82L20.32 14L12 14V18H20.32L17.14 21.18L19.98 24L28 16.02L19.98 8Z" />
 </vector>
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_screen_rotation.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_screen_rotation.xml
deleted file mode 100644
index 469eb1e..0000000
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_screen_rotation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2022 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/letterbox_education_dialog_icon_size"
-        android:height="@dimen/letterbox_education_dialog_icon_size"
-        android:viewportWidth="48"
-        android:viewportHeight="48">
-    <path
-        android:fillColor="@color/letterbox_education_text_secondary"
-        android:fillType="evenOdd"
-        android:pathData="M22.56 2H26C37.02 2 46 10.98 46 22H42C42 14.44 36.74 8.1 29.7 6.42L31.74 10L28.26 12L22.56 2ZM22 46H25.44L19.74 36L16.26 38L18.3 41.58C11.26 39.9 6 33.56 6 26H2C2 37.02 10.98 46 22 46ZM20.46 12L36 27.52L27.54 36L12 20.48L20.46 12ZM17.64 9.18C18.42 8.4 19.44 8 20.46 8C21.5 8 22.52 8.4 23.3 9.16L38.84 24.7C40.4 26.26 40.4 28.78 38.84 30.34L30.36 38.82C29.58 39.6 28.56 40 27.54 40C26.52 40 25.5 39.6 24.72 38.82L9.18 23.28C7.62 21.72 7.62 19.2 9.18 17.64L17.64 9.18Z" />
-</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml
index dcb8aed..15e65f7 100644
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml
+++ b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_split_screen.xml
@@ -15,18 +15,12 @@
   ~ limitations under the License.
   -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="@dimen/letterbox_education_dialog_icon_size"
-        android:height="@dimen/letterbox_education_dialog_icon_size"
-        android:viewportWidth="48"
-        android:viewportHeight="48">
+        android:width="@dimen/letterbox_education_dialog_icon_width"
+        android:height="@dimen/letterbox_education_dialog_icon_height"
+        android:viewportWidth="40"
+        android:viewportHeight="32">
+
     <path
         android:fillColor="@color/letterbox_education_text_secondary"
-        android:fillType="evenOdd"
-        android:pathData="M2 8C0.895431 8 0 8.89543 0 10V38C0 39.1046 0.895431 40 2 40H46C47.1046 40 48 39.1046 48 38V10C48 8.89543 47.1046 8 46 8H2ZM44 12H4V36H44V12Z" />
-    <path
-        android:fillColor="@color/letterbox_education_text_secondary"
-        android:pathData="M6 16C6 14.8954 6.89543 14 8 14H21C22.1046 14 23 14.8954 23 16V32C23 33.1046 22.1046 34 21 34H8C6.89543 34 6 33.1046 6 32V16Z" />
-    <path
-        android:fillColor="@color/letterbox_education_text_secondary"
-        android:pathData="M25 16C25 14.8954 25.8954 14 27 14H40C41.1046 14 42 14.8954 42 16V32C42 33.1046 41.1046 34 40 34H27C25.8954 34 25 33.1046 25 32V16Z" />
+        android:pathData="M40 28L40 4C40 1.8 38.2 -7.86805e-08 36 -1.74846e-07L26 -6.11959e-07C23.8 -7.08124e-07 22 1.8 22 4L22 28C22 30.2 23.8 32 26 32L36 32C38.2 32 40 30.2 40 28ZM14 28L4 28L4 4L14 4L14 28ZM18 28L18 4C18 1.8 16.2 -1.04033e-06 14 -1.1365e-06L4 -1.57361e-06C1.8 -1.66978e-06 -7.86805e-08 1.8 -1.74846e-07 4L-1.22392e-06 28C-1.32008e-06 30.2 1.8 32 4 32L14 32C16.2 32 18 30.2 18 28Z" />
 </vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/tv_split_menu_ic_focus.xml b/libs/WindowManager/Shell/res/drawable/tv_split_menu_ic_focus.xml
new file mode 100644
index 0000000..a348b14
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/tv_split_menu_ic_focus.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/tv_window_menu_icon_size"
+    android:height="@dimen/tv_window_menu_icon_size"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M17,4h3c1.1,0 2,0.9 2,2v2h-2L20,6h-3L17,4zM4,8L4,6h3L7,4L4,4c-1.1,0 -2,0.9 -2,2v2h2zM20,16v2h-3v2h3c1.1,0 2,-0.9 2,-2v-2h-2zM7,18L4,18v-2L2,16v2c0,1.1 0.9,2 2,2h3v-2zM18,8L6,8v8h12L18,8z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/drawable/tv_split_menu_ic_swap.xml b/libs/WindowManager/Shell/res/drawable/tv_split_menu_ic_swap.xml
new file mode 100644
index 0000000..c5d54c5
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/tv_split_menu_ic_swap.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/tv_window_menu_icon_size"
+    android:height="@dimen/tv_window_menu_icon_size"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M6.99,11L3,15l3.99,4v-3H14v-2H6.99v-3zM21,9l-3.99,-4v3H10v2h7.01v3L21,9z"/>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml
index cd1d99a..c65f24d 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_action_layout.xml
@@ -26,7 +26,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center"
-        android:layout_marginBottom="12dp"/>
+        android:layout_marginBottom="20dp"/>
 
     <TextView
         android:id="@+id/letterbox_education_dialog_action_text"
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
index 9592376..3a44eb9 100644
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml
@@ -50,13 +50,16 @@
                 android:layout_height="wrap_content"
                 android:gravity="center_horizontal"
                 android:orientation="vertical"
-                android:padding="24dp">
+                android:paddingTop="32dp"
+                android:paddingBottom="32dp"
+                android:paddingLeft="56dp"
+                android:paddingRight="56dp">
 
                 <ImageView
-                    android:layout_width="@dimen/letterbox_education_dialog_icon_size"
-                    android:layout_height="@dimen/letterbox_education_dialog_icon_size"
-                    android:layout_marginBottom="12dp"
-                    android:src="@drawable/letterbox_education_ic_letterboxed_app"/>
+                    android:layout_width="@dimen/letterbox_education_dialog_title_icon_width"
+                    android:layout_height="@dimen/letterbox_education_dialog_title_icon_height"
+                    android:layout_marginBottom="17dp"
+                    android:src="@drawable/letterbox_education_ic_light_bulb"/>
 
                 <TextView
                     android:id="@+id/letterbox_education_dialog_title"
@@ -68,16 +71,6 @@
                     android:textColor="@color/compat_controls_text"
                     android:textSize="24sp"/>
 
-                <TextView
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_marginTop="8dp"
-                    android:lineSpacingExtra="4sp"
-                    android:text="@string/letterbox_education_dialog_subtext"
-                    android:textAlignment="center"
-                    android:textColor="@color/letterbox_education_text_secondary"
-                    android:textSize="14sp"/>
-
                 <LinearLayout
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
@@ -88,16 +81,16 @@
                     <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        app:icon="@drawable/letterbox_education_ic_screen_rotation"
-                        app:text="@string/letterbox_education_screen_rotation_text"/>
+                        app:icon="@drawable/letterbox_education_ic_reposition"
+                        app:text="@string/letterbox_education_reposition_text"/>
 
                     <com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginStart=
                             "@dimen/letterbox_education_dialog_space_between_actions"
-                        app:icon="@drawable/letterbox_education_ic_reposition"
-                        app:text="@string/letterbox_education_reposition_text"/>
+                        app:icon="@drawable/letterbox_education_ic_split_screen"
+                        app:text="@string/letterbox_education_split_screen_text"/>
 
                 </LinearLayout>
 
@@ -105,7 +98,7 @@
                     android:id="@+id/letterbox_education_dialog_dismiss_button"
                     android:layout_width="match_parent"
                     android:layout_height="56dp"
-                    android:layout_marginTop="48dp"
+                    android:layout_marginTop="40dp"
                     android:background=
                         "@drawable/letterbox_education_dismiss_button_background_ripple"
                     android:text="@string/letterbox_education_got_it"
diff --git a/libs/WindowManager/Shell/res/layout/tv_split_menu_view.xml b/libs/WindowManager/Shell/res/layout/tv_split_menu_view.xml
new file mode 100644
index 0000000..e0fa59c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/tv_split_menu_view.xml
@@ -0,0 +1,125 @@
+<!--
+  ~ 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.
+  -->
+<!-- Layout for TvSplitMenuView -->
+<com.android.wm.shell.splitscreen.tv.TvSplitMenuView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center">
+
+        <LinearLayout
+            android:id="@+id/tv_split_main_menu"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            android:gravity="center">
+
+            <Space
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:gravity="center">
+
+                <com.android.wm.shell.common.TvWindowMenuActionButton
+                    android:id="@+id/tv_split_main_menu_focus_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/tv_split_menu_ic_focus" />
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:gravity="center">
+
+                <com.android.wm.shell.common.TvWindowMenuActionButton
+                    android:id="@+id/tv_split_main_menu_close_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/pip_ic_close_white" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <com.android.wm.shell.common.TvWindowMenuActionButton
+            android:id="@+id/tv_split_menu_swap_stages"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/tv_split_menu_ic_swap" />
+
+        <LinearLayout
+            android:id="@+id/tv_split_side_menu"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            android:gravity="center">
+
+            <Space
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:gravity="center">
+
+                <com.android.wm.shell.common.TvWindowMenuActionButton
+                    android:id="@+id/tv_split_side_menu_focus_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/tv_split_menu_ic_focus" />
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:gravity="center">
+
+                <com.android.wm.shell.common.TvWindowMenuActionButton
+                    android:id="@+id/tv_split_side_menu_close_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/pip_ic_close_white" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+    </LinearLayout>
+</com.android.wm.shell.splitscreen.tv.TvSplitMenuView>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index a57ce9d..40c4c35 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerakwessies?\nTik om aan te pas"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nie opgelos nie?\nTik om terug te stel"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen kamerakwessies nie? Tik om toe te maak."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sommige programme werk beter in portret"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Probeer een van hierdie opsies om jou spasie ten beste te benut"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Draai jou toestel om dit volskerm te maak"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dubbeltik langs ’n program om dit te herposisioneer"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Het dit"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vou uit vir meer inligting."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimeer"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index c1e1629..a183a0b 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"የካሜራ ችግሮች አሉ?\nዳግም ለማበጀት መታ ያድርጉ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"አልተስተካከለም?\nለማህደር መታ ያድርጉ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ምንም የካሜራ ችግሮች የሉም? ለማሰናበት መታ ያድርጉ።"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"አንዳንድ መተግበሪያዎች በቁም ፎቶ ውስጥ በተሻለ ሁኔታ ይሰራሉ"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ቦታዎን በአግባቡ ለመጠቀም ከእነዚህ አማራጮች ውስጥ አንዱን ይሞክሩ"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ወደ የሙሉ ገጽ ዕይታ ለመሄድ መሣሪያዎን ያሽከርክሩት"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ቦታውን ለመቀየር ከመተግበሪያው ቀጥሎ ላይ ሁለቴ መታ ያድርጉ"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ገባኝ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ለተጨማሪ መረጃ ይዘርጉ።"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"አስፋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 9a5a413..98f11dd 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"هل هناك مشاكل في الكاميرا؟\nانقر لإعادة الضبط."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ألم يتم حل المشكلة؟\nانقر للعودة"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"أليس هناك مشاكل في الكاميرا؟ انقر للإغلاق."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"تعمل بعض التطبيقات على أكمل وجه في الشاشات العمودية"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"جرِّب تنفيذ أحد هذه الخيارات للاستفادة من مساحتك إلى أقصى حد."</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"قم بتدوير الشاشة للانتقال إلى وضع ملء الشاشة."</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"انقر مرتين بجانب التطبيق لتغيير موضعه."</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"حسنًا"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"التوسيع للحصول على مزيد من المعلومات"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"تكبير"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index da3d3da..18cb3ff 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"কেমেৰাৰ কোনো সমস্যা হৈছে নেকি?\nপুনৰ খাপ খোৱাবলৈ টিপক"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এইটো সমাধান কৰা নাই নেকি?\nপূৰ্বাৱস্থালৈ নিবলৈ টিপক"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"কেমেৰাৰ কোনো সমস্যা নাই নেকি? অগ্ৰাহ্য কৰিবলৈ টিপক।"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"কিছুমান এপে প’ৰ্ট্ৰেইট ম’ডত বেছি ভালকৈ কাম কৰে"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"আপোনাৰ spaceৰ পৰা পাৰ্যমানে উপকৃত হ’বলৈ ইয়াৰে এটা বিকল্প চেষ্টা কৰি চাওক"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"পূৰ্ণ স্ক্ৰীনলৈ যাবলৈ আপোনাৰ ডিভাইচটো ঘূৰাওক"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"এপ্‌টোৰ স্থান সলনি কৰিবলৈ ইয়াৰ কাষত দুবাৰ টিপক"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"বুজি পালোঁ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"অধিক তথ্যৰ বাবে বিস্তাৰ কৰক।"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index bd7f8f0..2040288 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera problemi var?\nBərpa etmək üçün toxunun"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Düzəltməmisiniz?\nGeri qaytarmaq üçün toxunun"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera problemi yoxdur? Qapatmaq üçün toxunun."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Bəzi tətbiqlər portret rejimində daha yaxşı işləyir"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Məkanınızdan maksimum yararlanmaq üçün bu seçimlərdən birini sınayın"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Tam ekrana keçmək üçün cihazınızı fırladın"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tətbiqin yerini dəyişmək üçün yanına iki dəfə toxunun"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ətraflı məlumat üçün genişləndirin."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Böyüdün"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 114f791..b2b484e 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Imate problema sa kamerom?\nDodirnite da biste ponovo uklopili"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije rešen?\nDodirnite da biste vratili"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema sa kamerom? Dodirnite da biste odbacili."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Neke aplikacije najbolje funkcionišu u uspravnom režimu"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da biste na najbolji način iskoristili prostor"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotirajte uređaj za prikaz preko celog ekrana"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da biste promenili njenu poziciju"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Važi"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za još informacija."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Uvećajte"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 6ae5e42..59db992 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Праблемы з камерай?\nНацісніце, каб пераабсталяваць"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не ўдалося выправіць?\nНацісніце, каб аднавіць"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ніякіх праблем з камерай? Націсніце, каб адхіліць."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некаторыя праграмы лепш за ўсё працуюць у кніжнай арыентацыі"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Каб эфектыўна выкарыстоўваць прастору, паспрабуйце адзін з гэтых варыянтаў"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Каб перайсці ў поўнаэкранны рэжым, павярніце прыладу"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Двойчы націсніце побач з праграмай, каб перамясціць яе"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Зразумела"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгарнуць для дадатковай інфармацыі"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Разгарнуць"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index b11a8d4..8b5c4a9 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблеми с камерата?\nДокоснете за ремонтиране"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблемът не се отстрани?\nДокоснете за връщане в предишното състояние"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нямате проблеми с камерата? Докоснете, за да отхвърлите."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Някои приложения работят най-добре във вертикален режим"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Изпробвайте една от следните опции, за да се възползвате максимално от мястото на екрана"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Завъртете екрана си, за да преминете в режим на цял екран"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Докоснете два пъти дадено приложение, за да промените позицията му"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Разбрах"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Разгъване за още информация."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Увеличаване"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 6eab036..d7ff018 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ক্যামেরা সংক্রান্ত সমস্যা?\nরিফিট করতে ট্যাপ করুন"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"এখনও সমাধান হয়নি?\nরিভার্ট করার জন্য ট্যাপ করুন"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ক্যামেরা সংক্রান্ত সমস্যা নেই? বাতিল করতে ট্যাপ করুন।"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"কিছু অ্যাপ \'পোর্ট্রেট\' মোডে সবচেয়ে ভাল কাজ করে"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"আপনার স্পেস সবচেয়ে ভালভাবে কাজে লাগাতে এইসব বিকল্পের মধ্যে কোনও একটি ব্যবহার করে দেখুন"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"\'ফুল স্ক্রিন\' মোডে যেতে ডিভাইস ঘোরান"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"কোনও অ্যাপের পাশে ডবল ট্যাপ করে সেটির জায়গা পরিবর্তন করুন"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"বুঝেছি"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"আরও তথ্যের জন্য বড় করুন।"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"বড় করুন"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 8420b53..f4c4560 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s kamerom?\nDodirnite da ponovo namjestite"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nije popravljeno?\nDodirnite da vratite"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nema problema s kamerom? Dodirnite da odbacite."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Određene aplikacije najbolje funkcioniraju u uspravnom načinu rada"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da maksimalno iskoristite prostor"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zarotirajte uređaj da aktivirate prikaz preko cijelog ekrana"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da promijenite njen položaj"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Razumijem"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite za više informacija."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziranje"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index d4c1eea..c4e6b0d 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tens problemes amb la càmera?\nToca per resoldre\'ls"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"El problema no s\'ha resolt?\nToca per desfer els canvis"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No tens cap problema amb la càmera? Toca per ignorar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunes aplicacions funcionen millor en posició vertical"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prova una d\'aquestes opcions per treure el màxim profit de l\'espai"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gira el dispositiu per passar a pantalla completa"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Fes doble toc al costat d\'una aplicació per canviar-ne la posició"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entesos"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Desplega per obtenir més informació."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximitza"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 00034a6..8b0d1ff 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s fotoaparátem?\nKlepnutím vyřešíte"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepomohlo to?\nKlepnutím se vrátíte"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Žádné problémy s fotoaparátem? Klepnutím zavřete."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Některé aplikace fungují nejlépe na výšku"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pokud chcete maximálně využít prostor, vyzkoušejte jednu z těchto možností"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Otočením zařízení přejděte do režimu celé obrazovky"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvojitým klepnutím vedle aplikace změňte její umístění"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozbalením zobrazíte další informace."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovat"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 0dd1e1f..94faf412 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du problemer med dit kamera?\nTryk for at gendanne det oprindelige format"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Løste det ikke problemet?\nTryk for at fortryde"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen problemer med dit kamera? Tryk for at afvise."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Nogle apps fungerer bedst i stående format"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prøv én af disse muligheder for at få mest muligt ud af dit rum"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Drej din enhed for at gå til fuld skærm"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tryk to gange ud for en app for at ændre dens placering"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Udvid for at få flere oplysninger."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimér"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index ff7fed9..3971445 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -78,14 +78,15 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Probleme mit der Kamera?\nZum Anpassen tippen."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Das Problem ist nicht behoben?\nZum Rückgängigmachen tippen."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Keine Probleme mit der Kamera? Zum Schließen tippen."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Einige Apps funktionieren am besten im Hochformat"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Mithilfe dieser Möglichkeiten kannst du dein Display optimal nutzen"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gerät drehen, um zum Vollbildmodus zu wechseln"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Neben einer App doppeltippen, um die Position zu ändern"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ok"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Für weitere Informationen maximieren."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximieren"</string>
-    <!-- no translation found for minimize_button_text (271592547935841753) -->
-    <skip />
+    <string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string>
     <string name="close_button_text" msgid="2913281996024033299">"Schließen"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 634b446..023c2d6 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Προβλήματα με την κάμερα;\nΠατήστε για επιδιόρθωση."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Δεν διορθώθηκε;\nΠατήστε για επαναφορά."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Δεν αντιμετωπίζετε προβλήματα με την κάμερα; Πατήστε για παράβλεψη."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Ορισμένες εφαρμογές λειτουργούν καλύτερα σε κατακόρυφο προσανατολισμό"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Δοκιμάστε μία από αυτές τις επιλογές για να αξιοποιήσετε στο έπακρο τον χώρο σας."</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Περιστρέψτε τη συσκευή σας για μετάβαση σε πλήρη οθόνη."</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Πατήστε δύο φορές δίπλα σε μια εφαρμογή για να αλλάξετε τη θέση της."</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Το κατάλαβα"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ανάπτυξη για περισσότερες πληροφορίες."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Μεγιστοποίηση"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 431882f..acc75e4 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -78,10 +78,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+    <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+    <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+    <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 431882f..acc75e4 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -78,10 +78,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+    <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+    <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+    <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 431882f..acc75e4 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -78,10 +78,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+    <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+    <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+    <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 431882f..acc75e4 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -78,10 +78,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Camera issues?\nTap to refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Didn’t fix it?\nTap to revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"No camera issues? Tap to dismiss."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Some apps work best in portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Try one of these options to make the most of your space"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotate your device to go full screen"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Double-tap next to an app to reposition it"</string>
+    <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"See and do more"</string>
+    <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Drag in another app for split-screen"</string>
+    <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Double-tap outside an app to reposition it"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Got it"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expand for more information."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximise"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index 87b04e0..4e9f13f 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -78,10 +78,9 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‎Camera issues?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to refit‎‏‎‎‏‎"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎Didn’t fix it?‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Tap to revert‎‏‎‎‏‎"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‎No camera issues? Tap to dismiss.‎‏‎‎‏‎"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‏‏‎Some apps work best in portrait‎‏‎‎‏‎"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‎Try one of these options to make the most of your space‎‏‎‎‏‎"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎‎‏‏‎Rotate your device to go full screen‎‏‎‎‏‎"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎Double-tap next to an app to reposition it‎‏‎‎‏‎"</string>
+    <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‏‎‎See and do more‎‏‎‎‏‎"</string>
+    <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‎‎Drag in another app for split-screen‎‏‎‎‏‎"</string>
+    <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‏‏‎‏‎‏‎Double-tap outside an app to reposition it‎‏‎‎‏‎"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎‏‎Got it‎‏‎‎‏‎"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎‎Expand for more information.‎‏‎‎‏‎"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‏‎‏‏‎Maximize‎‏‎‎‏‎"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index 759fd4d..b5b6670 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Tienes problemas con la cámara?\nPresiona para reajustarla"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se resolvió?\nPresiona para revertir los cambios"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No tienes problemas con la cámara? Presionar para descartar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunas apps funcionan mejor en modo vertical"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prueba estas opciones para aprovechar al máximo tu espacio"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rota el dispositivo para ver la pantalla completa"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Presiona dos veces junto a una app para cambiar su posición"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expande para obtener más información."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index b2440bf..e38fc09 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"¿Problemas con la cámara?\nToca para reajustar"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"¿No se ha solucionado?\nToca para revertir"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"¿No hay problemas con la cámara? Toca para cerrar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunas aplicaciones funcionan mejor en vertical"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prueba una de estas opciones para sacar el máximo partido al espacio de tu pantalla"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gira el dispositivo para ir al modo de pantalla completa"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toca dos veces junto a una aplicación para cambiar su posición"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mostrar más información"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 60c29f8..f4684526 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kas teil on kaameraprobleeme?\nPuudutage ümberpaigutamiseks."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Kas probleemi ei lahendatud?\nPuudutage ennistamiseks."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kas kaameraprobleeme pole? Puudutage loobumiseks."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Mõni rakendus töötab kõige paremini vertikaalpaigutuses"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Proovige ühte neist valikutest, et oma ruumi parimal moel kasutada"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pöörake seadet, et aktiveerida täisekraanirežiim"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Topeltpuudutage rakenduse kõrval, et selle asendit muuta"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Selge"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Laiendage lisateabe saamiseks."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimeeri"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 6b0a88c..2c1ee82 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Arazoak dauzkazu kamerarekin?\nBerriro doitzeko, sakatu hau."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ez al da konpondu?\nLeheneratzeko, sakatu hau."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ez daukazu arazorik kamerarekin? Baztertzeko, sakatu hau."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Aplikazio batzuk orientazio bertikalean funtzionatzen dute hobekien"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pantailako eremuari ahalik eta etekinik handiena ateratzeko, probatu aukera hauetakoren bat"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pantaila osoko modua erabiltzeko, biratu gailua"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Aplikazioaren posizioa aldatzeko, sakatu birritan haren ondoko edozein toki"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ados"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Informazio gehiago lortzeko, zabaldu hau."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizatu"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 0a01b36..6b7bf4d 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"دوربین مشکل دارد؟\nبرای تنظیم مجدد اندازه ضربه بزنید"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"مشکل برطرف نشد؟\nبرای برگرداندن ضربه بزنید"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"دوربین مشکلی ندارد؟ برای بستن ضربه بزنید."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"برخی‌از برنامه‌ها در حالت عمودی عملکرد بهتری دارند"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"با امتحان کردن یکی از این گزینه‌ها، بیشترین بهره را از فضایتان ببرید"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"برای رفتن به حالت تمام صفحه، دستگاهتان را بچرخانید"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"در کنار برنامه دوضربه بزنید تا جابه‌جا شود"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"متوجه‌ام"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"برای اطلاعات بیشتر، گسترده کنید."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 6a7ecf1..b82a7cc 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Onko kameran kanssa ongelmia?\nKorjaa napauttamalla"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Eikö ongelma ratkennut?\nKumoa napauttamalla"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ei ongelmia kameran kanssa? Hylkää napauttamalla."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Osa sovelluksista toimii parhaiten pystytilassa"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Kokeile jotakin näistä vaihtoehdoista, jotta saat parhaan hyödyn näytön tilasta"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Käännä laitetta, niin se siirtyy koko näytön tilaan"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Kaksoisnapauta sovellusta, jos haluat siirtää sitä"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Katso lisätietoja laajentamalla."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Suurenna"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 5a7c505..449dc27 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo?\nTouchez pour réajuster"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu?\nTouchez pour rétablir"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo? Touchez pour ignorer."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Certaines applications fonctionnent mieux en mode portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Essayez l\'une de ces options pour tirer le meilleur parti de votre espace"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Faites pivoter votre appareil pour passer en plein écran"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Touchez deux fois à côté d\'une application pour la repositionner"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développer pour en savoir plus."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 7b1203e..15148b7 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problèmes d\'appareil photo ?\nAppuyez pour réajuster"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problème non résolu ?\nAppuyez pour rétablir"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Aucun problème d\'appareil photo ? Appuyez pour ignorer."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Certaines applis fonctionnent mieux en mode Portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Essayez l\'une de ces options pour exploiter pleinement l\'espace"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Faites pivoter l\'appareil pour passer en plein écran"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Appuyez deux fois à côté d\'une appli pour la repositionner"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Développez pour obtenir plus d\'informations"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index afb8a1e..b848fd0 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Tes problemas coa cámara?\nToca para reaxustala"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Non se solucionaron os problemas?\nToca para reverter o seu tratamento"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Non hai problemas coa cámara? Tocar para ignorar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algunhas aplicacións funcionan mellor en modo vertical"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Proba unha destas opcións para sacar o máximo proveito do espazo da pantalla"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Xira o dispositivo para ver o contido en pantalla completa"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toca dúas veces a carón dunha aplicación para cambiala de posición"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendido"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Despregar para obter máis información."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index 549c97a..79d27a2 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"કૅમેરામાં સમસ્યાઓ છે?\nફરીથી ફિટ કરવા માટે ટૅપ કરો"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"સુધારો નથી થયો?\nપહેલાંના પર પાછું ફેરવવા માટે ટૅપ કરો"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"કૅમેરામાં કોઈ સમસ્યા નથી? છોડી દેવા માટે ટૅપ કરો."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"અમુક ઍપ પોર્ટ્રેટ મોડમાં શ્રેષ્ઠ રીતે કાર્ય કરે છે"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"તમારી સ્પેસનો વધુને વધુ લાભ લેવા માટે, આ વિકલ્પોમાંથી કોઈ એક અજમાવો"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"પૂર્ણ સ્ક્રીન મોડ લાગુ કરવા માટે, તમારા ડિવાઇસને ફેરવો"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"કોઈ ઍપની જગ્યા બદલવા માટે, તેની બાજુમાં બે વાર ટૅપ કરો"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"સમજાઈ ગયું"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"વધુ માહિતી માટે મોટું કરો."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"મોટું કરો"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index 7a715c5..e803abe 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्या कैमरे से जुड़ी कोई समस्या है?\nफिर से फ़िट करने के लिए टैप करें"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"क्या समस्या ठीक नहीं हुई?\nपहले जैसा करने के लिए टैप करें"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्या कैमरे से जुड़ी कोई समस्या नहीं है? खारिज करने के लिए टैप करें."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"कुछ ऐप्लिकेशन, पोर्ट्रेट मोड में सबसे अच्छी तरह काम करते हैं"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"जगह का पूरा इस्तेमाल करने के लिए, इनमें से किसी एक विकल्प को आज़माएं"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"फ़ुल स्क्रीन मोड में जाने के लिए, डिवाइस को घुमाएं"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"किसी ऐप्लिकेशन की जगह बदलने के लिए, उसके बगल में दो बार टैप करें"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ठीक है"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ज़्यादा जानकारी के लिए बड़ा करें."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"बड़ा करें"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index e21eab0..07b946d 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi s fotoaparatom?\nDodirnite za popravak"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Problem nije riješen?\nDodirnite za vraćanje"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemate problema s fotoaparatom? Dodirnite za odbacivanje."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Neke aplikacije najbolje funkcioniraju u portretnom usmjerenju"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Isprobajte jednu od ovih opcija da biste maksimalno iskoristili prostor"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zakrenite uređaj radi prikaza na cijelom zaslonu"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvaput dodirnite pored aplikacije da biste joj promijenili položaj"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Shvaćam"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Proširite da biste saznali više."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziraj"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index eddb2fe..08b35bf 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamerával kapcsolatos problémába ütközött?\nKoppintson a megoldáshoz."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nem sikerült a hiba kijavítása?\nKoppintson a visszaállításhoz."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nincsenek problémái kamerával? Koppintson az elvetéshez."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Egyes alkalmazások álló tájolásban működnek a leghatékonyabban"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Próbálja ki az alábbi beállítások egyikét, hogy a legjobban ki tudja használni képernyő területét"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"A teljes képernyős mód elindításához forgassa el az eszközt"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Koppintson duplán az alkalmazás mellett az áthelyezéséhez"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Értem"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kibontással további információkhoz juthat."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Teljes méret"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 877ee61..9d81e8c 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Տեսախցիկի հետ կապված խնդիրնե՞ր կան։\nՀպեք՝ վերակարգավորելու համար։"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Չհաջողվե՞ց շտկել։\nՀպեք՝ փոփոխությունները չեղարկելու համար։"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Տեսախցիկի հետ կապված խնդիրներ չկա՞ն։ Փակելու համար հպեք։"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Որոշ հավելվածներ լավագույնս աշխատում են դիմանկարի ռեժիմում"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Փորձեք այս տարբերակներից մեկը՝ տարածքը հնարավորինս արդյունավետ օգտագործելու համար"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Պտտեք սարքը՝ լիաէկրան ռեժիմին անցնելու համար"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Կրկնակի հպեք հավելվածի կողքին՝ այն տեղափոխելու համար"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Եղավ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Ծավալեք՝ ավելին իմանալու համար։"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Ծավալել"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 4137948..f74e83f 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Masalah kamera?\nKetuk untuk memperbaiki"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tidak dapat diperbaiki?\nKetuk untuk mengembalikan"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tidak ada masalah kamera? Ketuk untuk menutup."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Beberapa aplikasi berfungsi paling baik dalam mode potret"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Coba salah satu opsi berikut untuk mengoptimalkan area layar Anda"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Putar perangkat untuk tampilan layar penuh"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ketuk dua kali di samping aplikasi untuk mengubah posisinya"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Oke"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Luaskan untuk melihat informasi selengkapnya."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimalkan"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index c7847fc0..71f6ec7 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Myndavélavesen?\nÝttu til að breyta stærð"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ennþá vesen?\nÝttu til að afturkalla"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Ekkert myndavélavesen? Ýttu til að hunsa."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sum forrit virka best í skammsniði"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prófaðu einhvern af eftirfarandi valkostum til að nýta plássið sem best"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Snúðu tækinu til að nota allan skjáinn"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ýttu tvisvar við hlið forritsins til að færa það"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ég skil"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Stækka til að sjá frekari upplýsingar."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Stækka"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 66e5160..45831356 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemi con la fotocamera?\nTocca per risolverli"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Il problema non si è risolto?\nTocca per ripristinare"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nessun problema con la fotocamera? Tocca per ignorare."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alcune app funzionano in modo ottimale in verticale"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prova una di queste opzioni per ottimizzare lo spazio a tua disposizione"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ruota il dispositivo per passare alla modalità a schermo intero"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tocca due volte accanto a un\'app per riposizionarla"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Espandi per avere ulteriori informazioni."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Ingrandisci"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index fa47100..bd52cd8 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"בעיות במצלמה?\nאפשר להקיש כדי לבצע התאמה מחדש"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"הבעיה לא נפתרה?\nאפשר להקיש כדי לחזור לגרסה הקודמת"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"אין בעיות במצלמה? אפשר להקיש כדי לסגור."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"חלק מהאפליקציות פועלות בצורה הטובה ביותר במצב תצוגה לאורך"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"כדי להפיק את המרב משטח המסך, ניתן לנסות את אחת מהאפשרויות האלה"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"מסובבים את המכשיר כדי לעבור לתצוגה במסך מלא"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"מקישים הקשה כפולה ליד אפליקציה כדי למקם אותה מחדש"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"הבנתי"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"מרחיבים כדי לקבל מידע נוסף."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"הגדלה"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 84798d2..98b3ba6 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"カメラに関する問題の場合は、\nタップすると修正できます"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"修正されなかった場合は、\nタップすると元に戻ります"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"カメラに関する問題でない場合は、タップすると閉じます。"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"アプリによっては縦向きにすると正常に動作します"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"スペースを最大限に活用するには、以下の方法のいずれかをお試しください"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"全画面表示にするにはデバイスを回転させてください"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"位置を変えるにはアプリの横をダブルタップしてください"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"開くと詳細が表示されます。"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 9a323c9..fbf0b5ec 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"კამერად პრობლემები აქვს?\nშეეხეთ გამოსასწორებლად"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"არ გამოსწორდა?\nშეეხეთ წინა ვერსიის დასაბრუნებლად"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"კამერას პრობლემები არ აქვს? შეეხეთ უარყოფისთვის."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ზოგიერთი აპი უკეთ მუშაობს პორტრეტის რეჟიმში"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"გამოცადეთ ამ ვარიანტებიდან ერთ-ერთი, რათა მაქსიმალურად ისარგებლოთ თქვენი მეხსიერებით"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"მოატრიალეთ თქვენი მოწყობილობა სრული ეკრანის გასაშლელად"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ორმაგად შეეხეთ აპის გვერდითა სივრცეს, რათა ის სხვაგან გადაიტანოთ"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"გასაგებია"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"დამატებითი ინფორმაციისთვის გააფართოეთ."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"მაქსიმალურად გაშლა"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index f910693..a75dc3c 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада қателер шықты ма?\nЖөндеу үшін түртіңіз."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Жөнделмеді ме?\nҚайтару үшін түртіңіз."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада қателер шықпады ма? Жабу үшін түртіңіз."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Кейбір қолданба портреттік режимде жақсы жұмыс істейді"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Экранды тиімді пайдалану үшін мына опциялардың бірін байқап көріңіз."</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Толық экранға ауысу үшін құрылғыңызды бұрыңыз."</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Қолданбаның орнын ауыстыру үшін жанынан екі рет түртіңіз."</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Түсінікті"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толығырақ ақпарат алу үшін терезені жайыңыз."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Жаю"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 51f9c4f..6913c06 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"មានបញ្ហា​ពាក់ព័ន្ធនឹង​កាមេរ៉ាឬ?\nចុចដើម្បី​ដោះស្រាយ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"មិនបាន​ដោះស្រាយ​បញ្ហានេះទេឬ?\nចុចដើម្បី​ត្រឡប់"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"មិនមាន​បញ្ហាពាក់ព័ន្ធនឹង​កាមេរ៉ាទេឬ? ចុចដើម្បី​ច្រានចោល។"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"កម្មវិធីមួយចំនួនដំណើរការបានប្រសើរបំផុតក្នុងទិសដៅបញ្ឈរ"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"សាកល្បងជម្រើសមួយក្នុងចំណោមទាំងនេះ ដើម្បីទទួលបានអត្ថប្រយោជន៍ច្រើនបំផុតពីកន្លែងទំនេររបស់អ្នក"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"បង្វិលឧបករណ៍របស់អ្នក ដើម្បីចូលប្រើអេក្រង់ពេញ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ចុចពីរដងនៅជាប់កម្មវិធីណាមួយ ដើម្បីប្ដូរទីតាំងកម្មវិធីនោះ"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"យល់ហើយ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ពង្រីកដើម្បីទទួលបានព័ត៌មានបន្ថែម។"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ពង្រីក"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 36ba9f7..1f246d5 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿವೆಯೇ?\nಮರುಹೊಂದಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ಅದನ್ನು ಸರಿಪಡಿಸಲಿಲ್ಲವೇ?\nಹಿಂತಿರುಗಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ಕ್ಯಾಮರಾ ಸಮಸ್ಯೆಗಳಿಲ್ಲವೇ? ವಜಾಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ಕೆಲವು ಆ್ಯಪ್‌ಗಳು ಪೋರ್ಟ್ರೇಟ್ ಮೋಡ್‌ನಲ್ಲಿ ಅತ್ಯುತ್ತಮವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತವೆ"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ನಿಮ್ಮ ಸ್ಥಳಾವಕಾಶದ ಅತಿಹೆಚ್ಚು ಪ್ರಯೋಜನ ಪಡೆಯಲು ಈ ಆಯ್ಕೆಗಳಲ್ಲಿ ಒಂದನ್ನು ಬಳಸಿ ನೋಡಿ"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ಪೂರ್ಣ ಸ್ಕ್ರೀನ್‌ಗೆ ಹೋಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ತಿರುಗಿಸಿ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ಆ್ಯಪ್ ಒಂದರ ಸ್ಥಾನವನ್ನು ಬದಲಾಯಿಸಲು ಅದರ ಪಕ್ಕದಲ್ಲಿ ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ಸರಿ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ಇನ್ನಷ್ಟು ಮಾಹಿತಿಗಾಗಿ ವಿಸ್ತೃತಗೊಳಿಸಿ."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ಹಿಗ್ಗಿಸಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 2c7c3fc..e878cef 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"카메라 문제가 있나요?\n해결하려면 탭하세요."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"해결되지 않았나요?\n되돌리려면 탭하세요."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"카메라에 문제가 없나요? 닫으려면 탭하세요."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"일부 앱은 세로 모드에서 가장 잘 작동함"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"공간을 최대한 이용할 수 있도록 이 옵션 중 하나를 시도해 보세요."</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"전체 화면 모드로 전환하려면 기기를 회전하세요."</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"앱 위치를 조정하려면 앱 옆을 두 번 탭하세요."</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"확인"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"추가 정보는 펼쳐서 확인하세요."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"최대화"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 5a487e6..20c462e 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерада маселелер келип чыктыбы?\nОңдоо үчүн таптаңыз"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Оңдолгон жокпу?\nАртка кайтаруу үчүн таптаңыз"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерада маселе жокпу? Этибарга албоо үчүн таптаңыз."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Айрым колдонмолорду тигинен иштетүү туура болот"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Иш чөйрөсүнүн бардык мүмкүнчүлүктөрүн пайдалануу үчүн бул параметрлердин бирин колдонуп көрүңүз"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Толук экран режимине өтүү үчүн түзмөктү буруңуз"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Колдонмонун ракурсун өзгөртүү үчүн анын тушуна эки жолу басыңыз"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Түшүндүм"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Толук маалымат алуу үчүн жайып көрүңүз."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Чоңойтуу"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 558ca62..3f4a881 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ?\nແຕະເພື່ອປັບໃໝ່"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ບໍ່ໄດ້ແກ້ໄຂມັນບໍ?\nແຕະເພື່ອແປງກັບຄືນ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ບໍ່ມີບັນຫາກ້ອງຖ່າຍຮູບບໍ? ແຕະເພື່ອ​ປິດ​ໄວ້."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ແອັບບາງຢ່າງເຮັດວຽກໄດ້ດີທີ່ສຸດໃນໂໝດລວງຕັ້ງ"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ໃຫ້ລອງຕົວເລືອກໃດໜຶ່ງເຫຼົ່ານີ້ເພື່ອໃຊ້ປະໂຫຍດຈາກພື້ນທີ່ຂອງທ່ານໃຫ້ໄດ້ສູງສຸດ"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ໝຸນອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ແບບເຕັມຈໍ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ແຕະສອງເທື່ອໃສ່ຖັດຈາກແອັບໃດໜຶ່ງເພື່ອຈັດຕຳແໜ່ງຂອງມັນຄືນໃໝ່"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ເຂົ້າໃຈແລ້ວ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ຂະຫຍາຍເພື່ອເບິ່ງຂໍ້ມູນເພີ່ມເຕີມ."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 88a6ac9..515a263 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Iškilo problemų dėl kameros?\nPalieskite, kad pritaikytumėte iš naujo"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nepavyko pataisyti?\nPalieskite, kad grąžintumėte"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nėra jokių problemų dėl kameros? Palieskite, kad atsisakytumėte."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Kai kurios programos geriausiai veikia stačiuoju režimu"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Pabandykite naudoti vieną iš šių parinkčių, kad išnaudotumėte visą vietą"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pasukite įrenginį, kad įjungtumėte viso ekrano režimą"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dukart palieskite šalia programos, kad pakeistumėte jos poziciją"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Supratau"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Išskleiskite, jei reikia daugiau informacijos."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Padidinti"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index fbb3539..080c6f4 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Vai ir problēmas ar kameru?\nPieskarieties, lai tās novērstu."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Vai problēma netika novērsta?\nPieskarieties, lai atjaunotu."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Vai nav problēmu ar kameru? Pieskarieties, lai nerādītu."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Dažas lietotnes vislabāk darbojas portreta režīmā"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Izmēģiniet vienu no šīm iespējām, lai efektīvi izmantotu pieejamo vietu"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Pagrieziet ierīci, lai aktivizētu pilnekrāna režīmu"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Veiciet dubultskārienu blakus lietotnei, lai manītu tās pozīciju"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Labi"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Izvērsiet, lai iegūtu plašāku informāciju."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimizēt"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index e1ab00a8..47ed632 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми со камерата?\nДопрете за да се совпадне повторно"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не се поправи?\nДопрете за враќање"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нема проблеми со камерата? Допрете за отфрлање."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некои апликации најдобро работат во режим на портрет"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Испробајте една од опцииве за да го извлечете максимумот од вашиот простор"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ротирајте го уредот за да отворите на цел екран"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Допрете двапати до некоја апликација за да ја преместите"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Сфатив"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширете за повеќе информации."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Зголеми"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index 1072dac..faa6a30f 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ക്യാമറ പ്രശ്നങ്ങളുണ്ടോ?\nശരിയാക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"അത് പരിഹരിച്ചില്ലേ?\nപുനഃസ്ഥാപിക്കാൻ ടാപ്പ് ചെയ്യുക"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ക്യാമറാ പ്രശ്നങ്ങളൊന്നുമില്ലേ? നിരസിക്കാൻ ടാപ്പ് ചെയ്യുക."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ചില ആപ്പുകൾ പോർട്രെയ്റ്റിൽ മികച്ച രീതിയിൽ പ്രവർത്തിക്കുന്നു"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"നിങ്ങളുടെ ഇടം പരമാവധി പ്രയോജനപ്പെടുത്താൻ ഈ ഓപ്ഷനുകളിലൊന്ന് പരീക്ഷിക്കുക"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"പൂർണ്ണ സ്ക്രീനിലേക്ക് മാറാൻ ഈ ഉപകരണം റൊട്ടേറ്റ് ചെയ്യുക"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ഒരു ആപ്പിന്റെ സ്ഥാനം മാറ്റാൻ, അതിന് തൊട്ടടുത്ത് ഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"മനസ്സിലായി"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"കൂടുതൽ വിവരങ്ങൾക്ക് വികസിപ്പിക്കുക."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"വലുതാക്കുക"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index 4210b8d..8e8d06d 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Камерын асуудал гарсан уу?\nДахин тааруулахын тулд товшино уу"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Үүнийг засаагүй юу?\nБуцаахын тулд товшино уу"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Камерын асуудал байхгүй юу? Хаахын тулд товшино уу."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Зарим апп нь босоо чиглэлд хамгийн сайн ажилладаг"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Орон зайгаа сайтар ашиглахын тулд эдгээр сонголтуудын аль нэгийг туршиж үзээрэй"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Төхөөрөмжөө бүтэн дэлгэцээр үзэхийн тулд эргүүлнэ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Аппыг дахин байрлуулахын тулд хажууд нь хоёр товшино"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ойлголоо"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Нэмэлт мэдээлэл авах бол дэлгэнэ үү."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Томруулах"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 396e2129..4fc03b2 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"कॅमेराशी संबंधित काही समस्या आहेत का?\nपुन्हा फिट करण्यासाठी टॅप करा"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"निराकरण झाले नाही?\nरिव्हर्ट करण्यासाठी कृपया टॅप करा"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"कॅमेराशी संबंधित कोणत्याही समस्या नाहीत का? डिसमिस करण्‍यासाठी टॅप करा."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"काही ॲप्स पोर्ट्रेटमध्ये सर्वोत्तम काम करतात"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"तुमच्या स्पेसचा पुरेपूर वापर करण्यासाठी, यांपैकी एक पर्याय वापरून पहा"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"फुल स्क्रीन करण्यासाठी, तुमचे डिव्हाइस फिरवा"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ॲपची स्थिती पुन्हा बदलण्यासाठी, त्याच्या शेजारी दोनदा टॅप करा"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"समजले"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"अधिक माहितीसाठी विस्तार करा."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"मोठे करा"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index f7a65bba..2db225a 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Isu kamera?\nKetik untuk memuatkan semula"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Isu tidak dibetulkan?\nKetik untuk kembali"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Tiada isu kamera? Ketik untuk mengetepikan."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sesetengah apl berfungsi paling baik dalam mod potret"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Cuba salah satu daripada pilihan ini untuk memanfaatkan ruang anda sepenuhnya"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Putar peranti anda untuk beralih ke skrin penuh"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Ketik dua kali bersebelahan apl untuk menempatkan semula apl"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Kembangkan untuk mendapatkan maklumat lanjut."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimumkan"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 217c15b..e8ab4b0 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ကင်မရာပြဿနာလား။\nပြင်ဆင်ရန် တို့ပါ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ကောင်းမသွားဘူးလား။\nပြန်ပြောင်းရန် တို့ပါ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ကင်မရာပြဿနာ မရှိဘူးလား။ ပယ်ရန် တို့ပါ။"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"အချို့အက်ပ်များသည် ဒေါင်လိုက်တွင် အကောင်းဆုံးလုပ်ဆောင်သည်"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"သင့်နေရာကို အကောင်းဆုံးအသုံးပြုနိုင်ရန် ဤရွေးစရာများထဲမှ တစ်ခုကို စမ်းကြည့်ပါ"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ဖန်သားပြင်အပြည့်လုပ်ရန် သင့်စက်ကို လှည့်နိုင်သည်"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"အက်ပ်နေရာပြန်ချရန် ၎င်းဘေးတွင် နှစ်ချက်တို့နိုင်သည်"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ရပြီ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"နောက်ထပ်အချက်အလက်များအတွက် ချဲ့နိုင်သည်။"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ချဲ့ရန်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 6d5e481..278de2d 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Har du kameraproblemer?\nTrykk for å tilpasse"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Ble ikke problemet løst?\nTrykk for å gå tilbake"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Har du ingen kameraproblemer? Trykk for å lukke."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Noen apper fungerer best i stående format"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Prøv et av disse alternativene for å få mest mulig ut av plassen din"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Roter enheten for å starte fullskjerm"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dobbelttrykk ved siden av en app for å flytte den"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Greit"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Vis for å få mer informasjon."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimer"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 6e84d8a..529f401 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"क्यामेरासम्बन्धी समस्या देखियो?\nसमस्या हल गर्न ट्याप गर्नुहोस्"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"समस्या हल भएन?\nपहिलेको जस्तै बनाउन ट्याप गर्नुहोस्"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"क्यामेरासम्बन्धी कुनै पनि समस्या छैन? खारेज गर्न ट्याप गर्नुहोस्।"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"केही एपहरूले पोर्ट्रेटमा राम्रोसँग काम गर्छन्"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"तपाईं स्क्रिनको अधिकतम ठाउँ प्रयोग गर्न चाहनुहुन्छ भने यीमध्ये कुनै विकल्प प्रयोग गरी हेर्नुहोस्"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"तपाईं फुल स्क्रिन मोड हेर्न चाहनुहुन्छ भने आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"तपाईं जुन एपको स्थिति मिलाउन चाहनुहुन्छ सोही एपको छेउमा डबल ट्याप गर्नुहोस्"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"बुझेँ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"थप जानकारी प्राप्त गर्न चाहनुहुन्छ भने एक्स्पान्ड गर्नुहोस्।"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ठुलो बनाउनुहोस्"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index e24ecb3..88c220c 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Cameraproblemen?\nTik om opnieuw passend te maken."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Is dit geen oplossing?\nTik om terug te zetten."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Geen cameraproblemen? Tik om te sluiten."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Sommige apps werken het best in de staande stand"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Probeer een van deze opties om optimaal gebruik te maken van je ruimte"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Draai je apparaat om naar volledig scherm te schakelen"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dubbeltik naast een app om deze opnieuw te positioneren"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Uitvouwen voor meer informatie."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximaliseren"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 74e9261..2c82fbc 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"କ୍ୟାମେରାରେ ସମସ୍ୟା ଅଛି?\nପୁଣି ଫିଟ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ଏହାର ସମାଧାନ ହୋଇନାହିଁ?\nଫେରିଯିବା ପାଇଁ ଟାପ କରନ୍ତୁ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"କ୍ୟାମେରାରେ କିଛି ସମସ୍ୟା ନାହିଁ? ଖାରଜ କରିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"କିଛି ଆପ ପୋର୍ଟ୍ରେଟରେ ସବୁଠାରୁ ଭଲ କାମ କରେ"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ଆପଣଙ୍କ ସ୍ପେସରୁ ଅଧିକ ଲାଭ ପାଇବାକୁ ଏହି ବିକଳ୍ପଗୁଡ଼ିକ ମଧ୍ୟରୁ ଗୋଟିଏ ବ୍ୟବହାର କରି ଦେଖନ୍ତୁ"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ପୂର୍ଣ୍ଣ-ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ରୋଟେଟ କରନ୍ତୁ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ଏକ ଆପକୁ ରିପୋଜିସନ କରିବା ପାଇଁ ଏହା ପାଖରେ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ବୁଝିଗଲି"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ଅଧିକ ସୂଚନା ପାଇଁ ବିସ୍ତାର କରନ୍ତୁ।"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ବଡ଼ କରନ୍ତୁ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index cd5de57..8c7229f 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ?\nਮੁੜ-ਫਿੱਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"ਕੀ ਇਹ ਠੀਕ ਨਹੀਂ ਹੋਈ?\nਵਾਪਸ ਉਹੀ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"ਕੀ ਕੈਮਰੇ ਸੰਬੰਧੀ ਕੋਈ ਸਮੱਸਿਆ ਨਹੀਂ ਹੈ? ਖਾਰਜ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"ਕੁਝ ਐਪਾਂ ਪੋਰਟਰੇਟ ਵਿੱਚ ਬਿਹਤਰ ਕੰਮ ਕਰਦੀਆਂ ਹਨ"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ਆਪਣੀ ਜਗ੍ਹਾ ਦਾ ਵੱਧ ਤੋਂ ਵੱਧ ਲਾਹਾ ਲੈਣ ਲਈ ਇਨ੍ਹਾਂ ਵਿਕਲਪਾਂ ਵਿੱਚੋਂ ਕੋਈ ਇੱਕ ਵਰਤ ਕੇ ਦੇਖੋ"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ਪੂਰੀ-ਸਕ੍ਰੀਨ ਮੋਡ \'ਤੇ ਜਾਣ ਲਈ ਆਪਣੇ ਡੀਵਾਈਸ ਨੂੰ ਘੁਮਾਓ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ਕਿਸੇ ਐਪ ਦੀ ਜਗ੍ਹਾ ਬਦਲਣ ਲਈ ਉਸ ਦੇ ਅੱਗੇ ਡਬਲ ਟੈਪ ਕਰੋ"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ਸਮਝ ਲਿਆ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਵਿਸਤਾਰ ਕਰੋ।"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ਵੱਡਾ ਕਰੋ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 4ee0cb8..315b95e 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemy z aparatem?\nKliknij, aby dopasować"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Naprawa się nie udała?\nKliknij, aby cofnąć"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Brak problemów z aparatem? Kliknij, aby zamknąć"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Niektóre aplikacje działają najlepiej w orientacji pionowej"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Wypróbuj jedną z tych opcji, aby jak najlepiej wykorzystać miejsce"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Obróć urządzenie, aby przejść do pełnego ekranu"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Kliknij dwukrotnie obok aplikacji, aby ją przenieść"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Rozwiń, aby wyświetlić więcej informacji."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksymalizuj"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 4f59329..48781ad 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alguns apps funcionam melhor em modo retrato"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Tente uma destas opções para aproveitar seu espaço ao máximo"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gire o dispositivo para entrar no modo de tela cheia"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes ao lado de um app para reposicionar"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 37c5acf..e2be183 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmara?\nToque aqui para reajustar"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Não foi corrigido?\nToque para reverter"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nenhum problema com a câmara? Toque para ignorar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Algumas apps funcionam melhor no modo vertical"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Experimente uma destas opções para aproveitar ao máximo o seu espaço"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rode o dispositivo para ficar em ecrã inteiro"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes junto a uma app para a reposicionar"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Expandir para obter mais informações"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 4f59329..48781ad 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problemas com a câmera?\nToque para ajustar o enquadramento"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"O problema não foi corrigido?\nToque para reverter"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Não tem problemas com a câmera? Toque para dispensar."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Alguns apps funcionam melhor em modo retrato"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Tente uma destas opções para aproveitar seu espaço ao máximo"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Gire o dispositivo para entrar no modo de tela cheia"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Toque duas vezes ao lado de um app para reposicionar"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Entendi"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Abra para ver mais informações."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 88b582e..65b0472 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Aveți probleme cu camera foto?\nAtingeți pentru a reîncadra"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ați remediat problema?\nAtingeți pentru a reveni"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu aveți probleme cu camera foto? Atingeți pentru a închide."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Unele aplicații funcționează cel mai bine în orientarea portret"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Încercați una dintre aceste opțiuni pentru a profita din plin de spațiu"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotiți dispozitivul pentru a trece în modul ecran complet"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Atingeți de două ori lângă o aplicație pentru a o repoziționa"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extindeți pentru mai multe informații"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximizați"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index 07d5dbb..8affb9a 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблемы с камерой?\nНажмите, чтобы исправить."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Не помогло?\nНажмите, чтобы отменить изменения."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Нет проблем с камерой? Нажмите, чтобы закрыть."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Некоторые приложения лучше работают в вертикальном режиме"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Чтобы эффективно использовать экранное пространство, выполните одно из следующих действий:"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Чтобы перейти в полноэкранный режим, поверните устройство."</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Чтобы переместить приложение, нажмите на него дважды."</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ОК"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Развернуть, чтобы узнать больше."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Развернуть"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index dc23f81..c816065 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"කැමරා ගැටලුද?\nයළි සවි කිරීමට තට්ටු කරන්න"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"එය විසඳුවේ නැතිද?\nප්‍රතිවර්තනය කිරීමට තට්ටු කරන්න"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"කැමරා ගැටලු නොමැතිද? ඉවත දැමීමට තට්ටු කරන්න"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"සමහර යෙදුම් ප්‍රතිමූර්තිය තුළ හොඳින්ම ක්‍රියා කරයි"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ඔබගේ ඉඩෙන් උපරිම ප්‍රයෝජන ගැනීමට මෙම විකල්පවලින් එකක් උත්සාහ කරන්න"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"සම්පූර්ණ තිරයට යාමට ඔබගේ උපාංගය කරකවන්න"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"එය නැවත ස්ථානගත කිරීමට යෙදුමකට යාබදව දෙවරක් තට්ටු කරන්න"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"තේරුණා"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"වැඩිදුර තොරතුරු සඳහා දිග හරින්න"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"විහිදන්න"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index 53cb218..9dfbd54 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problémy s kamerou?\nKlepnutím znova upravte."</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nevyriešilo sa to?\nKlepnutím sa vráťte."</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nemáte problémy s kamerou? Klepnutím zatvoríte."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Niektoré aplikácie fungujú najlepšie v režime na výšku"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Vyskúšajte jednu z týchto možností a využívajte svoj priestor naplno"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Otočením zariadenia prejdete do režimu celej obrazovky"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvojitým klepnutím vedľa aplikácie zmeníte jej pozíciu"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Dobre"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Po rozbalení sa dozviete viac."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maximalizovať"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index 27197bc..5bf943b 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Težave s fotoaparatom?\nDotaknite se za vnovično prilagoditev"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"To ni odpravilo težave?\nDotaknite se za povrnitev"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nimate težav s fotoaparatom? Dotaknite se za opustitev."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Nekatere aplikacije najbolje delujejo v navpični postavitvi"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Poskusite eno od teh možnosti za čim boljši izkoristek prostora"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Če želite preklopiti v celozaslonski način, zasukajte napravo."</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Dvakrat se dotaknite ob aplikaciji, če jo želite prestaviti."</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"V redu"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Razširitev za več informacij"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiraj"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 64ef538..0955999 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ka probleme me kamerën?\nTrokit për ta ripërshtatur"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nuk u rregullua?\nTrokit për ta rikthyer"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nuk ka probleme me kamerën? Trokit për ta shpërfillur."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Disa aplikacione funksionojnë më mirë në modalitetin vertikal"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Provo një nga këto opsione për ta shfrytëzuar sa më mirë hapësirën"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rrotullo ekranin për të kaluar në ekran të plotë"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Trokit dy herë pranë një aplikacioni për ta ripozicionuar"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"E kuptova"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Zgjeroje për më shumë informacion."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Maksimizo"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index fe31879..b42d98e4 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Имате проблема са камером?\nДодирните да бисте поново уклопили"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблем није решен?\nДодирните да бисте вратили"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немате проблема са камером? Додирните да бисте одбацили."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Неке апликације најбоље функционишу у усправном режиму"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Испробајте једну од ових опција да бисте на најбољи начин искористили простор"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Ротирајте уређај за приказ преко целог екрана"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Двапут додирните поред апликације да бисте променили њену позицију"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Важи"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Проширите за још информација."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Увећајте"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 2745838..162b57d 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Problem med kameran?\nTryck för att anpassa på nytt"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Löstes inte problemet?\nTryck för att återställa"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Inga problem med kameran? Tryck för att ignorera."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Vissa appar fungerar bäst i stående läge"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Testa med ett av dessa alternativ för att få ut mest möjliga av ytan"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Rotera skärmen för att gå över till helskärmsläge"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Tryck snabbt två gånger bredvid en app för att flytta den"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Utöka för mer information."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Utöka"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 565ecc4..3844d01 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Je, kuna hitilafu za kamera?\nGusa ili urekebishe"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Umeshindwa kurekebisha?\nGusa ili urejeshe nakala ya awali"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Je, hakuna hitilafu za kamera? Gusa ili uondoe."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Baadhi ya programu hufanya kazi vizuri zaidi zikiwa wima"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Jaribu moja kati ya chaguo hizi ili utumie nafasi ya skrini yako kwa ufanisi"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zungusha kifaa chako ili uende kwenye hali ya skrini nzima"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Gusa mara mbili karibu na programu ili uihamishe"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Nimeelewa"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Panua ili upate maelezo zaidi."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Panua"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index a5244d2..c45409c 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"கேமரா தொடர்பான சிக்கல்களா?\nமீண்டும் பொருத்த தட்டவும்"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"சிக்கல்கள் சரிசெய்யப்படவில்லையா?\nமாற்றியமைக்க தட்டவும்"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"கேமரா தொடர்பான சிக்கல்கள் எதுவும் இல்லையா? நிராகரிக்க தட்டவும்."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"சில ஆப்ஸ் \'போர்ட்ரெய்ட்டில்\' சிறப்பாகச் செயல்படும்"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ஸ்பேஸ்களிலிருந்து அதிகப் பலன்களைப் பெற இந்த விருப்பங்களில் ஒன்றைப் பயன்படுத்துங்கள்"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"முழுத்திரைக்குச் செல்ல உங்கள் சாதனத்தைச் சுழற்றவும்"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"ஆப்ஸை இடம் மாற்ற, ஆப்ஸுக்கு அடுத்து இருமுறை தட்டவும்"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"சரி"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"கூடுதல் தகவல்களுக்கு விரிவாக்கலாம்."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"பெரிதாக்கும்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index ee7c376..0a61f93 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"కెమెరా సమస్యలు ఉన్నాయా?\nరీఫిట్ చేయడానికి ట్యాప్ చేయండి"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"దాని సమస్యను పరిష్కరించలేదా?\nపూర్వస్థితికి మార్చడానికి ట్యాప్ చేయండి"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"కెమెరా సమస్యలు లేవా? తీసివేయడానికి ట్యాప్ చేయండి."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"కొన్ని యాప్‌లు పోర్ట్రెయిట్‌లో ఉత్తమంగా పని చేస్తాయి"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"మీ ప్రదేశాన్ని ఎక్కువగా ఉపయోగించుకోవడానికి ఈ ఆప్షన్‌లలో ఒకదాన్ని ట్రై చేయండి"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"ఫుల్ స్క్రీన్‌కు వెళ్లడానికి మీ పరికరాన్ని తిప్పండి"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"యాప్ స్థానాన్ని మార్చడానికి దాని పక్కన డబుల్-ట్యాప్ చేయండి"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"అర్థమైంది"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"మరింత సమాచారం కోసం విస్తరించండి."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"గరిష్టీకరించండి"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 6b1498b..0a41d45 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"หากพบปัญหากับกล้อง\nแตะเพื่อแก้ไข"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"หากไม่ได้แก้ไข\nแตะเพื่อเปลี่ยนกลับ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"หากไม่พบปัญหากับกล้อง แตะเพื่อปิด"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"บางแอปทำงานได้ดีที่สุดในแนวตั้ง"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"ลองใช้หนึ่งในตัวเลือกเหล่านี้เพื่อให้ได้ประโยชน์สูงสุดจากพื้นที่ว่าง"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"หมุนอุปกรณ์ให้แสดงเต็มหน้าจอ"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"แตะสองครั้งข้างแอปเพื่อเปลี่ยนตำแหน่ง"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"รับทราบ"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"ขยายเพื่อดูข้อมูลเพิ่มเติม"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"ขยายใหญ่สุด"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index c6a3776..e272799 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"May mga isyu sa camera?\nI-tap para i-refit"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Hindi ito naayos?\nI-tap para i-revert"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Walang isyu sa camera? I-tap para i-dismiss."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"May ilang app na pinakamainam gamitin nang naka-portrait"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Subukan ang isa sa mga opsyong ito para masulit ang iyong space"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"I-rotate ang iyong device para mag-full screen"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Mag-double tap sa tabi ng isang app para iposisyon ito ulit"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"I-expand para sa higit pang impormasyon."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"I-maximize"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 6014998..050fa5f 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kameranızda sorun mu var?\nDüzeltmek için dokunun"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bu işlem sorunu düzeltmedi mi?\nİşlemi geri almak için dokunun"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kameranızda sorun yok mu? Kapatmak için dokunun."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Bazı uygulamalar dikey modda en iyi performansı gösterir"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Alanınızı en verimli şekilde kullanmak için bu seçeneklerden birini deneyin"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Tam ekrana geçmek için cihazınızı döndürün"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Yeniden konumlandırmak için uygulamanın yanına iki kez dokunun"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Anladım"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Daha fazla bilgi için genişletin."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Ekranı Kapla"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index a07d28a..d5f047f 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Проблеми з камерою?\nНатисніть, щоб пристосувати"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Проблему не вирішено?\nНатисніть, щоб скасувати зміни"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Немає проблем із камерою? Торкніться, щоб закрити."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Деякі додатки найкраще працюють у вертикальній орієнтації"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Щоб максимально ефективно використовувати місце на екрані, спробуйте виконати одну з наведених нижче дій"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Щоб перейти в повноекранний режим, поверніть пристрій"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Щоб перемістити додаток, двічі торкніться області поруч із ним"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"ОK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Розгорніть, щоб дізнатися більше."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Збільшити"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index d651cda..700ecaa 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"کیمرے کے مسائل؟\nدوبارہ فٹ کرنے کیلئے تھپتھپائیں"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"یہ حل نہیں ہوا؟\nلوٹانے کیلئے تھپتھپائیں"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"کوئی کیمرے کا مسئلہ نہیں ہے؟ برخاست کرنے کیلئے تھپتھپائیں۔"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"کچھ ایپس پورٹریٹ میں بہترین کام کرتی ہیں"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"اپنی اسپیس کا زیادہ سے زیادہ فائدہ اٹھانے کے لیے ان اختیارات میں سے ایک کو آزمائیں"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"پوری اسکرین پر جانے کیلئے اپنا آلہ گھمائیں"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"کسی ایپ کی پوزیشن تبدیل کرنے کے لیے اس کے آگے دو بار تھپتھپائیں"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"سمجھ آ گئی"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"مزید معلومات کے لیے پھیلائیں۔"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"بڑا کریں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 9e1d871..e843b0b 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Kamera nosozmi?\nQayta moslash uchun bosing"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Tuzatilmadimi?\nQaytarish uchun bosing"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Kamera muammosizmi? Yopish uchun bosing."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Ayrim ilovalar tik holatda ishlashga eng mos"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Muhitdan yanada samarali foydalanish uchun quyidagilardan birini sinang"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Butun ekranda ochish uchun qurilmani buring"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Qayta joylash uchun keyingi ilova ustiga ikki marta bosing"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Batafsil axborot olish uchun kengaytiring."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Yoyish"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index f50e28b..ec1eadb 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Có vấn đề với máy ảnh?\nHãy nhấn để sửa lỗi"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Bạn chưa khắc phục vấn đề?\nHãy nhấn để hủy bỏ"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Không có vấn đề với máy ảnh? Hãy nhấn để đóng."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Một số ứng dụng hoạt động tốt nhất ở chế độ dọc"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Hãy thử một trong các tuỳ chọn sau để tận dụng không gian"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Xoay thiết bị để chuyển sang chế độ toàn màn hình"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Nhấn đúp vào bên cạnh ứng dụng để đặt lại vị trí"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Mở rộng để xem thêm thông tin."</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Phóng to"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index a01acfd..37d4244 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相机有问题?\n点按即可整修"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"没有解决此问题?\n点按即可恢复"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相机没有问题?点按即可忽略。"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"某些应用在纵向模式下才能发挥最佳效果"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"这些选项都有助于您最大限度地利用屏幕空间,不妨从中择一试试"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋转设备即可进入全屏模式"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在某个应用旁边连续点按两次,即可调整它的位置"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展开即可了解详情。"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index 6d9a820..170cd4c 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題?\n輕按即可修正"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未能修正問題?\n輕按即可還原"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機冇問題?㩒一下就可以即可閂咗佢。"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"部分應用程式需要使用直向模式才能發揮最佳效果"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"請嘗試以下選項,充分運用螢幕的畫面空間"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋轉裝置方向即可進入全螢幕模式"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在應用程式旁輕按兩下即可調整位置"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"知道了"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳情。"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 431ef18..83f8520 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"相機有問題嗎?\n輕觸即可修正"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"未修正問題嗎?\n輕觸即可還原"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"相機沒問題嗎?輕觸即可關閉。"</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"某些應用程式在直向模式下才能發揮最佳效果"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"請試試這裡的任一方式,以充分運用螢幕畫面的空間"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"旋轉裝置方向即可進入全螢幕模式"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"在應用程式旁輕觸兩下即可調整位置"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"我知道了"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"展開即可查看詳細資訊。"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index 514b7b6..686310a 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -78,10 +78,12 @@
     <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Izinkinga zekhamera?\nThepha ukuze uyilinganise kabusha"</string>
     <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Akuyilungisanga?\nThepha ukuze ubuyele"</string>
     <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Azikho izinkinga zekhamera? Thepha ukuze ucashise."</string>
-    <string name="letterbox_education_dialog_title" msgid="6688664582871779215">"Amanye ama-app asebenza ngcono uma eme ngobude"</string>
-    <string name="letterbox_education_dialog_subtext" msgid="4853542518367719562">"Zama enye yalezi zinketho ukuze usebenzise isikhala sakho ngokugcwele"</string>
-    <string name="letterbox_education_screen_rotation_text" msgid="5085786687366339027">"Zungezisa idivayisi yakho ukuze uye esikrinini esigcwele"</string>
-    <string name="letterbox_education_reposition_text" msgid="1068293354123934727">"Thepha kabili eduze kwe-app ukuze uyimise kabusha"</string>
+    <!-- no translation found for letterbox_education_dialog_title (7739895354143295358) -->
+    <skip />
+    <!-- no translation found for letterbox_education_split_screen_text (6206339484068670830) -->
+    <skip />
+    <!-- no translation found for letterbox_education_reposition_text (4589957299813220661) -->
+    <skip />
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"Ngiyezwa"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Nweba ukuze uthole ulwazi olwengeziwe"</string>
     <string name="maximize_button_text" msgid="1650859196290301963">"Khulisa"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 1dac9ca..5696b8d 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -81,6 +81,9 @@
     <!-- The width and height of the background for custom action in PiP menu. -->
     <dimen name="pip_custom_close_bg_size">32dp</dimen>
 
+    <!-- Extra padding between picture-in-picture windows and any registered keep clear areas. -->
+    <dimen name="pip_keep_clear_areas_padding">16dp</dimen>
+
     <dimen name="dismiss_target_x_size">24dp</dimen>
     <dimen name="floating_dismiss_bottom_margin">50dp</dimen>
 
@@ -246,8 +249,17 @@
     <!-- The corner radius of the letterbox education dialog. -->
     <dimen name="letterbox_education_dialog_corner_radius">28dp</dimen>
 
-    <!-- The size of an icon in the letterbox education dialog. -->
-    <dimen name="letterbox_education_dialog_icon_size">48dp</dimen>
+    <!-- The width of the top icon in the letterbox education dialog. -->
+    <dimen name="letterbox_education_dialog_title_icon_width">45dp</dimen>
+
+    <!-- The height of the top icon in the letterbox education dialog. -->
+    <dimen name="letterbox_education_dialog_title_icon_height">44dp</dimen>
+
+    <!-- The width of an icon in the letterbox education dialog. -->
+    <dimen name="letterbox_education_dialog_icon_width">40dp</dimen>
+
+    <!-- The height of an icon in the letterbox education dialog. -->
+    <dimen name="letterbox_education_dialog_icon_height">32dp</dimen>
 
     <!-- The fixed width of the dialog if there is enough space in the parent. -->
     <dimen name="letterbox_education_dialog_width">472dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 679bfb9..b48a508 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -177,16 +177,13 @@
     <string name="camera_compat_dismiss_button_description">No camera issues? Tap to dismiss.</string>
 
     <!-- The title of the letterbox education dialog. [CHAR LIMIT=NONE] -->
-    <string name="letterbox_education_dialog_title">Some apps work best in portrait</string>
+    <string name="letterbox_education_dialog_title">See and do more</string>
 
-    <!-- The subtext of the letterbox education dialog. [CHAR LIMIT=NONE] -->
-    <string name="letterbox_education_dialog_subtext">Try one of these options to make the most of your space</string>
-
-    <!-- Description of the rotate screen action. [CHAR LIMIT=NONE] -->
-    <string name="letterbox_education_screen_rotation_text">Rotate your device to go full screen</string>
+    <!-- Description of the split screen action. [CHAR LIMIT=NONE] -->
+    <string name="letterbox_education_split_screen_text">Drag in another app for split-screen</string>
 
     <!-- Description of the reposition app action. [CHAR LIMIT=NONE] -->
-    <string name="letterbox_education_reposition_text">Double-tap next to an app to reposition it</string>
+    <string name="letterbox_education_reposition_text">Double-tap outside an app to reposition it</string>
 
     <!-- Button text for dismissing the letterbox education dialog. [CHAR LIMIT=20] -->
     <string name="letterbox_education_got_it">Got it</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
new file mode 100644
index 0000000..d276002
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -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.wm.shell;
+
+import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.wm.shell.sysui.ShellCommandHandler;
+import com.android.wm.shell.sysui.ShellInit;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
+/**
+ * Controls the {@link ShellProtoLogImpl} in WMShell via adb shell commands.
+ *
+ * Use with {@code adb shell dumpsys activity service SystemUIService WMShell protolog ...}.
+ */
+public class ProtoLogController implements ShellCommandHandler.ShellCommandActionHandler {
+    private final ShellCommandHandler mShellCommandHandler;
+    private final ShellProtoLogImpl mShellProtoLog;
+
+    public ProtoLogController(ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler) {
+        shellInit.addInitCallback(this::onInit, this);
+        mShellCommandHandler = shellCommandHandler;
+        mShellProtoLog = ShellProtoLogImpl.getSingleInstance();
+    }
+
+    void onInit() {
+        mShellCommandHandler.addCommandCallback("protolog", this, this);
+    }
+
+    @Override
+    public boolean onShellCommand(String[] args, PrintWriter pw) {
+        switch (args[0]) {
+            case "status": {
+                pw.println(mShellProtoLog.getStatus());
+                return true;
+            }
+            case "start": {
+                mShellProtoLog.startProtoLog(pw);
+                return true;
+            }
+            case "stop": {
+                mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
+                return true;
+            }
+            case "enable-text": {
+                String[] groups = Arrays.copyOfRange(args, 1, args.length);
+                int result = mShellProtoLog.startTextLogging(groups, pw);
+                if (result == 0) {
+                    pw.println("Starting logging on groups: " + Arrays.toString(groups));
+                    return true;
+                }
+                return false;
+            }
+            case "disable-text": {
+                String[] groups = Arrays.copyOfRange(args, 1, args.length);
+                int result = mShellProtoLog.stopTextLogging(groups, pw);
+                if (result == 0) {
+                    pw.println("Stopping logging on groups: " + Arrays.toString(groups));
+                    return true;
+                }
+                return false;
+            }
+            case "enable": {
+                String[] groups = Arrays.copyOfRange(args, 1, args.length);
+                return mShellProtoLog.startTextLogging(groups, pw) == 0;
+            }
+            case "disable": {
+                String[] groups = Arrays.copyOfRange(args, 1, args.length);
+                return mShellProtoLog.stopTextLogging(groups, pw) == 0;
+            }
+            default: {
+                pw.println("Invalid command: " + args[0]);
+                printShellCommandHelp(pw, "");
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public void printShellCommandHelp(PrintWriter pw, String prefix) {
+        pw.println(prefix + "status");
+        pw.println(prefix + "  Get current ProtoLog status.");
+        pw.println(prefix + "start");
+        pw.println(prefix + "  Start proto logging.");
+        pw.println(prefix + "stop");
+        pw.println(prefix + "  Stop proto logging and flush to file.");
+        pw.println(prefix + "enable [group...]");
+        pw.println(prefix + "  Enable proto logging for given groups.");
+        pw.println(prefix + "disable [group...]");
+        pw.println(prefix + "  Disable proto logging for given groups.");
+        pw.println(prefix + "enable-text [group...]");
+        pw.println(prefix + "  Enable logcat logging for given groups.");
+        pw.println(prefix + "disable-text [group...]");
+        pw.println(prefix + "  Disable logcat logging for given groups.");
+    }
+}
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 d5d4935..4367936 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell;
 
+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;
@@ -695,15 +696,19 @@
     /**
      * Create a {@link WindowContainerTransaction} to clear task bounds.
      *
+     * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to
+     * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+     *
      * @param displayId display id for tasks that will have bounds cleared
      * @return {@link WindowContainerTransaction} with pending operations to clear bounds
      */
-    public WindowContainerTransaction prepareClearBoundsForTasks(int displayId) {
+    public WindowContainerTransaction prepareClearBoundsForStandardTasks(int displayId) {
         ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks: displayId=%d", displayId);
         WindowContainerTransaction wct = new WindowContainerTransaction();
         for (int i = 0; i < mTasks.size(); i++) {
             RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
-            if (taskInfo.displayId == displayId) {
+            if ((taskInfo.displayId == displayId) && (taskInfo.getActivityType()
+                    == WindowConfiguration.ACTIVITY_TYPE_STANDARD)) {
                 ProtoLog.d(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
                         taskInfo.token, taskInfo);
                 wct.setBounds(taskInfo.token, null);
@@ -715,17 +720,21 @@
     /**
      * Create a {@link WindowContainerTransaction} to clear task level freeform setting.
      *
+     * Only affects tasks that have {@link RunningTaskInfo#getActivityType()} set to
+     * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+     *
      * @param displayId display id for tasks that will have windowing mode reset to {@link
      *                  WindowConfiguration#WINDOWING_MODE_UNDEFINED}
      * @return {@link WindowContainerTransaction} with pending operations to clear windowing mode
      */
-    public WindowContainerTransaction prepareClearFreeformForTasks(int displayId) {
+    public WindowContainerTransaction prepareClearFreeformForStandardTasks(int displayId) {
         ProtoLog.d(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks: displayId=%d", displayId);
         WindowContainerTransaction wct = new WindowContainerTransaction();
         for (int i = 0; i < mTasks.size(); i++) {
             RunningTaskInfo taskInfo = mTasks.valueAt(i).getTaskInfo();
             if (taskInfo.displayId == displayId
-                    && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
+                    && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
+                    && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
                 ProtoLog.d(WM_SHELL_DESKTOP_MODE,
                         "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
                         taskInfo);
@@ -867,8 +876,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/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 dcbb272..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);
 
@@ -1387,9 +1376,6 @@
 
             if (update.selectionChanged && mStackView != null) {
                 mStackView.setSelectedBubble(update.selectedBubble);
-                if (update.selectedBubble != null) {
-                    mSysuiProxy.updateNotificationSuppression(update.selectedBubble.getKey());
-                }
             }
 
             // Expanding? Apply this last.
@@ -1448,7 +1434,6 @@
                     // in the shade, it is essentially removed.
                     Bubble bubbleChild = mBubbleData.getAnyBubbleWithkey(child.getKey());
                     if (bubbleChild != null) {
-                        mSysuiProxy.removeNotificationEntry(bubbleChild.getKey());
                         bubbleChild.setSuppressNotification(true);
                         bubbleChild.setShowDot(false /* show */);
                     }
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/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 0e97e9e..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,14 +276,8 @@
 
         void notifyInvalidateNotifications(String reason);
 
-        void notifyMaybeCancelSummary(String key);
-
-        void removeNotificationEntry(String key);
-
         void updateNotificationBubbleButton(String key);
 
-        void updateNotificationSuppression(String key);
-
         void onStackExpandChanged(boolean shouldExpand);
 
         void onManageMenuExpandChanged(boolean menuExpanded);
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/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index b7959eb..4c85d20 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
@@ -80,7 +80,10 @@
     public static final int PARALLAX_DISMISSING = 1;
     public static final int PARALLAX_ALIGN_CENTER = 2;
 
-    private static final int FLING_ANIMATION_DURATION = 250;
+    private static final int FLING_RESIZE_DURATION = 250;
+    private static final int FLING_SWITCH_DURATION = 350;
+    private static final int FLING_ENTER_DURATION = 350;
+    private static final int FLING_EXIT_DURATION = 350;
 
     private final int mDividerWindowWidth;
     private final int mDividerInsets;
@@ -93,6 +96,9 @@
     private final Rect mBounds1 = new Rect();
     // Bounds2 final position should be always at bottom or right
     private final Rect mBounds2 = new Rect();
+    // The temp bounds outside of display bounds for side stage when split screen inactive to avoid
+    // flicker next time active split screen.
+    private final Rect mInvisibleBounds = new Rect();
     private final Rect mWinBounds1 = new Rect();
     private final Rect mWinBounds2 = new Rect();
     private final SplitLayoutHandler mSplitLayoutHandler;
@@ -141,6 +147,8 @@
         resetDividerPosition();
 
         mDimNonImeSide = resources.getBoolean(R.bool.config_dimNonImeAttachedSide);
+
+        updateInvisibleRect();
     }
 
     private int getDividerInsets(Resources resources, Display display) {
@@ -239,6 +247,12 @@
         rect.offset(-mRootBounds.left, -mRootBounds.top);
     }
 
+    /** Gets bounds size equal to root bounds but outside of screen, used for position side stage
+     * when split inactive to avoid flicker when next time active. */
+    public void getInvisibleBounds(Rect rect) {
+        rect.set(mInvisibleBounds);
+    }
+
     /** Returns leash of the current divider bar. */
     @Nullable
     public SurfaceControl getDividerLeash() {
@@ -258,6 +272,14 @@
                 : (float) ((mBounds1.bottom + mBounds2.top) / 2f) / mBounds2.bottom));
     }
 
+    private void updateInvisibleRect() {
+        mInvisibleBounds.set(mRootBounds.left, mRootBounds.top,
+                isLandscape() ? mRootBounds.right / 2 : mRootBounds.right,
+                isLandscape() ? mRootBounds.bottom : mRootBounds.bottom / 2);
+        mInvisibleBounds.offset(isLandscape() ? mRootBounds.right : 0,
+                isLandscape() ? 0 : mRootBounds.bottom);
+    }
+
     /** Applies new configuration, returns {@code false} if there's no effect to the layout. */
     public boolean updateConfiguration(Configuration configuration) {
         // Update the split bounds when necessary. Besides root bounds changed, split bounds need to
@@ -283,6 +305,7 @@
         mRotation = rotation;
         mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         initDividerPosition(mTempRect);
+        updateInvisibleRect();
 
         return true;
     }
@@ -405,6 +428,13 @@
         mFreezeDividerWindow = freezeDividerWindow;
     }
 
+    /** Update current layout as divider put on start or end position. */
+    public void setDividerAtBorder(boolean start) {
+        final int pos = start ? mDividerSnapAlgorithm.getDismissStartTarget().position
+                : mDividerSnapAlgorithm.getDismissEndTarget().position;
+        setDividePosition(pos, false /* applyLayoutChange */);
+    }
+
     /**
      * Updates bounds with the passing position. Usually used to update recording bounds while
      * performing animation or dragging divider bar to resize the splits.
@@ -449,17 +479,17 @@
     public void snapToTarget(int currentPosition, DividerSnapAlgorithm.SnapTarget snapTarget) {
         switch (snapTarget.flag) {
             case FLAG_DISMISS_START:
-                flingDividePosition(currentPosition, snapTarget.position,
+                flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
                         () -> mSplitLayoutHandler.onSnappedToDismiss(false /* bottomOrRight */,
                                 EXIT_REASON_DRAG_DIVIDER));
                 break;
             case FLAG_DISMISS_END:
-                flingDividePosition(currentPosition, snapTarget.position,
+                flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
                         () -> mSplitLayoutHandler.onSnappedToDismiss(true /* bottomOrRight */,
                                 EXIT_REASON_DRAG_DIVIDER));
                 break;
             default:
-                flingDividePosition(currentPosition, snapTarget.position,
+                flingDividePosition(currentPosition, snapTarget.position, FLING_RESIZE_DURATION,
                         () -> setDividePosition(snapTarget.position, true /* applyLayoutChange */));
                 break;
         }
@@ -514,12 +544,20 @@
     public void flingDividerToDismiss(boolean toEnd, int reason) {
         final int target = toEnd ? mDividerSnapAlgorithm.getDismissEndTarget().position
                 : mDividerSnapAlgorithm.getDismissStartTarget().position;
-        flingDividePosition(getDividePosition(), target,
+        flingDividePosition(getDividePosition(), target, FLING_EXIT_DURATION,
                 () -> mSplitLayoutHandler.onSnappedToDismiss(toEnd, reason));
     }
 
+    /** Fling divider from current position to center position. */
+    public void flingDividerToCenter() {
+        final int pos = mDividerSnapAlgorithm.getMiddleTarget().position;
+        flingDividePosition(getDividePosition(), pos, FLING_ENTER_DURATION,
+                () -> setDividePosition(pos, true /* applyLayoutChange */));
+    }
+
     @VisibleForTesting
-    void flingDividePosition(int from, int to, @Nullable Runnable flingFinishedCallback) {
+    void flingDividePosition(int from, int to, int duration,
+            @Nullable Runnable flingFinishedCallback) {
         if (from == to) {
             // No animation run, still callback to stop resizing.
             mSplitLayoutHandler.onLayoutSizeChanged(this);
@@ -529,7 +567,7 @@
         }
         ValueAnimator animator = ValueAnimator
                 .ofInt(from, to)
-                .setDuration(FLING_ANIMATION_DURATION);
+                .setDuration(duration);
         animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         animator.addUpdateListener(
                 animation -> updateDivideBounds((int) animation.getAnimatedValue()));
@@ -586,7 +624,7 @@
 
         AnimatorSet set = new AnimatorSet();
         set.playTogether(animator1, animator2, animator3);
-        set.setDuration(FLING_ANIMATION_DURATION);
+        set.setDuration(FLING_SWITCH_DURATION);
         set.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
index 15bfeb2..e9957fd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java
@@ -16,16 +16,32 @@
 
 package com.android.wm.shell.dagger;
 
-import android.view.IWindowManager;
+import android.content.Context;
+import android.os.Handler;
 
+import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.SystemWindows;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+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.tv.TvSplitScreenController;
 import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm;
 import com.android.wm.shell.startingsurface.tv.TvStartingWindowTypeAlgorithm;
+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.Transitions;
+
+import java.util.Optional;
 
 import dagger.Module;
 import dagger.Provides;
@@ -50,5 +66,33 @@
     @DynamicOverride
     static StartingWindowTypeAlgorithm provideStartingWindowTypeAlgorithm() {
         return new TvStartingWindowTypeAlgorithm();
-    };
+    }
+
+    @WMSingleton
+    @Provides
+    @DynamicOverride
+    static SplitScreenController provideSplitScreenController(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            ShellController shellController,
+            ShellTaskOrganizer shellTaskOrganizer,
+            SyncTransactionQueue syncQueue,
+            RootTaskDisplayAreaOrganizer rootTDAOrganizer,
+            DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
+            DragAndDropController dragAndDropController,
+            Transitions transitions,
+            TransactionPool transactionPool,
+            IconProvider iconProvider,
+            Optional<RecentTasksController> recentTasks,
+            @ShellMainThread ShellExecutor mainExecutor,
+            Handler mainHandler,
+            SystemWindows systemWindows) {
+        return new TvSplitScreenController(context, shellInit, shellCommandHandler, shellController,
+                shellTaskOrganizer, syncQueue, rootTDAOrganizer, displayController,
+                displayImeController, displayInsetsController, dragAndDropController, transitions,
+                transactionPool, iconProvider, recentTasks, mainExecutor, mainHandler,
+                systemWindows);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 7a736cc..c39602032 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -27,6 +27,7 @@
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.ProtoLogController;
 import com.android.wm.shell.RootDisplayAreaOrganizer;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -699,6 +700,7 @@
             Optional<ActivityEmbeddingController> activityEmbeddingOptional,
             Transitions transitions,
             StartingWindowController startingWindow,
+            ProtoLogController protoLogController,
             @ShellCreateTriggerOverride Optional<Object> overriddenCreateTrigger) {
         return new Object();
     }
@@ -714,4 +716,12 @@
     static ShellCommandHandler provideShellCommandHandler() {
         return new ShellCommandHandler();
     }
+
+    @WMSingleton
+    @Provides
+    static ProtoLogController provideProtoLogController(
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler) {
+        return new ProtoLogController(shellInit, shellCommandHandler);
+    }
 }
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 31596f3..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
@@ -49,7 +49,7 @@
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ShellBackgroundThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.desktopmode.DesktopModeConstants;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.freeform.FreeformComponents;
@@ -72,9 +72,9 @@
 import com.android.wm.shell.pip.PipTransitionController;
 import com.android.wm.shell.pip.PipTransitionState;
 import com.android.wm.shell.pip.PipUiEventLogger;
+import com.android.wm.shell.pip.phone.PhonePipKeepClearAlgorithm;
 import com.android.wm.shell.pip.phone.PhonePipMenuController;
 import com.android.wm.shell.pip.phone.PipController;
-import com.android.wm.shell.pip.phone.PipKeepClearAlgorithm;
 import com.android.wm.shell.pip.phone.PipMotionHelper;
 import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.recents.RecentTasksController;
@@ -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);
     }
 
@@ -320,7 +321,7 @@
             DisplayController displayController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
-            PipKeepClearAlgorithm pipKeepClearAlgorithm,
+            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
             PipBoundsState pipBoundsState,
             PipMotionHelper pipMotionHelper,
             PipMediaController pipMediaController,
@@ -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
@@ -357,15 +359,17 @@
 
     @WMSingleton
     @Provides
-    static PipKeepClearAlgorithm providePipKeepClearAlgorithm() {
-        return new PipKeepClearAlgorithm();
+    static PhonePipKeepClearAlgorithm providePhonePipKeepClearAlgorithm(Context context) {
+        return new PhonePipKeepClearAlgorithm(context);
     }
 
     @WMSingleton
     @Provides
     static PipBoundsAlgorithm providesPipBoundsAlgorithm(Context context,
-            PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm) {
-        return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm);
+            PipBoundsState pipBoundsState, PipSnapAlgorithm pipSnapAlgorithm,
+            PhonePipKeepClearAlgorithm pipKeepClearAlgorithm) {
+        return new PipBoundsAlgorithm(context, pipBoundsState, pipSnapAlgorithm,
+                pipKeepClearAlgorithm);
     }
 
     // Handler is used by Icon.loadDrawableAsync
@@ -481,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);
     }
 
     //
@@ -597,7 +601,7 @@
             RootDisplayAreaOrganizer rootDisplayAreaOrganizer,
             @ShellMainThread Handler mainHandler
     ) {
-        if (DesktopModeConstants.IS_FEATURE_ENABLED) {
+        if (DesktopMode.IS_SUPPORTED) {
             return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
                     rootDisplayAreaOrganizer,
                     mainHandler));
@@ -616,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
new file mode 100644
index 0000000..8993d54
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.internal.protolog.common.ProtoLog;
+
+/**
+ * Constants for desktop mode feature
+ */
+public class DesktopMode {
+
+    /**
+     * Flag to indicate whether desktop mode is available on the device
+     */
+    public static final boolean IS_SUPPORTED = SystemProperties.getBoolean(
+            "persist.wm.debug.desktop_mode", false);
+
+    /**
+     * Check if desktop mode is active
+     *
+     * @return {@code true} if active
+     */
+    public static boolean isActive(Context context) {
+        if (!IS_SUPPORTED) {
+            return false;
+        }
+        try {
+            int result = Settings.System.getIntForUser(context.getContentResolver(),
+                    Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
+            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
+            return result != 0;
+        } catch (Exception e) {
+            ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
+            return false;
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 5849e16..7d34ea4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -62,25 +62,29 @@
     private void onInit() {
         ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
         mSettingsObserver.observe();
+        if (DesktopMode.isActive(mContext)) {
+            updateDesktopModeActive(true);
+        }
     }
 
     @VisibleForTesting
-    void updateDesktopModeEnabled(boolean enabled) {
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeState: enabled=%s", enabled);
+    void updateDesktopModeActive(boolean active) {
+        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeActive: active=%s", active);
 
         int displayId = mContext.getDisplayId();
 
         WindowContainerTransaction wct = new WindowContainerTransaction();
         // Reset freeform windowing mode that is set per task level (tasks should inherit
         // container value)
-        wct.merge(mShellTaskOrganizer.prepareClearFreeformForTasks(displayId), true /* transfer */);
+        wct.merge(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(displayId),
+                true /* transfer */);
         int targetWindowingMode;
-        if (enabled) {
+        if (active) {
             targetWindowingMode = WINDOWING_MODE_FREEFORM;
         } else {
             targetWindowingMode = WINDOWING_MODE_FULLSCREEN;
             // Clear any resized bounds
-            wct.merge(mShellTaskOrganizer.prepareClearBoundsForTasks(displayId),
+            wct.merge(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(displayId),
                     true /* transfer */);
         }
         wct.merge(mRootDisplayAreaOrganizer.prepareWindowingModeChange(displayId,
@@ -118,20 +122,8 @@
         }
 
         private void desktopModeSettingChanged() {
-            boolean enabled = isDesktopModeEnabled();
-            updateDesktopModeEnabled(enabled);
-        }
-
-        private boolean isDesktopModeEnabled() {
-            try {
-                int result = Settings.System.getIntForUser(mContext.getContentResolver(),
-                        Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
-                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
-                return result != 0;
-            } catch (Settings.SettingNotFoundException e) {
-                ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
-                return false;
-            }
+            boolean enabled = DesktopMode.isActive(mContext);
+            updateDesktopModeActive(enabled);
         }
     }
 }
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/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
index dd50fa0..fd4c85fa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java
@@ -92,6 +92,12 @@
 
 
     @Override
+    public void startRemoveTransition(WindowContainerTransaction wct) {
+        final int type = WindowManager.TRANSIT_CLOSE;
+        mPendingTransitionTokens.add(mTransitions.startTransition(type, wct, this));
+    }
+
+    @Override
     public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startT,
             @NonNull SurfaceControl.Transaction finishT,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
index c947cf1..8da4c6a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionStarter.java
@@ -40,4 +40,12 @@
      *
      */
     void startMinimizedModeTransition(WindowContainerTransaction wct);
+
+    /**
+     * Starts close window transition
+     *
+     * @param wct the {@link WindowContainerTransaction} that closes the task
+     *
+     */
+    void startRemoveTransition(WindowContainerTransaction wct);
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 0d75bc4..e9f9bb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -105,8 +105,8 @@
         state.mTaskInfo = taskInfo;
         mTasks.put(taskInfo.taskId, state);
 
-        updateRecentsForVisibleFullscreenTask(taskInfo);
         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
+        updateRecentsForVisibleFullscreenTask(taskInfo);
         if (shouldShowWindowDecor(taskInfo) && mWindowDecorViewModelOptional.isPresent()) {
             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
             state.mWindowDecoration =
@@ -135,8 +135,8 @@
             mWindowDecorViewModelOptional.get().onTaskInfoChanged(
                     state.mTaskInfo, state.mWindowDecoration);
         }
-        updateRecentsForVisibleFullscreenTask(taskInfo);
         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
+        updateRecentsForVisibleFullscreenTask(taskInfo);
 
         final Point positionInParent = state.mTaskInfo.positionInParent;
         if (!oldPositionInParent.equals(state.mTaskInfo.positionInParent)) {
@@ -287,6 +287,9 @@
     }
 
     private void releaseWindowDecor(T windowDecor) {
+        if (windowDecor == null) {
+            return;
+        }
         try {
             windowDecor.close();
         } catch (Exception e) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index e03421d..4def15d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -37,12 +37,13 @@
      * @param activityInfo ActivityInfo tied to the Activity
      * @param pictureInPictureParams PictureInPictureParams tied to the Activity
      * @param launcherRotation Launcher rotation to calculate the PiP destination bounds
-     * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds
+     * @param hotseatKeepClearArea Bounds of Hotseat to avoid used to calculate PiP destination
+              bounds
      * @return destination bounds the PiP window should land into
      */
     Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo,
                 in PictureInPictureParams pictureInPictureParams,
-                int launcherRotation, int shelfHeight) = 1;
+                int launcherRotation, in Rect hotseatKeepClearArea) = 1;
 
     /**
      * Notifies the swiping Activity to PiP onto home transition is finished
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
index 7397e52..cd61dbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsAlgorithm.java
@@ -47,6 +47,7 @@
 
     private final @NonNull PipBoundsState mPipBoundsState;
     private final PipSnapAlgorithm mSnapAlgorithm;
+    private final PipKeepClearAlgorithm mPipKeepClearAlgorithm;
 
     private float mDefaultSizePercent;
     private float mMinAspectRatioForMinSize;
@@ -60,9 +61,11 @@
     protected Point mScreenEdgeInsets;
 
     public PipBoundsAlgorithm(Context context, @NonNull PipBoundsState pipBoundsState,
-            @NonNull PipSnapAlgorithm pipSnapAlgorithm) {
+            @NonNull PipSnapAlgorithm pipSnapAlgorithm,
+            @NonNull PipKeepClearAlgorithm pipKeepClearAlgorithm) {
         mPipBoundsState = pipBoundsState;
         mSnapAlgorithm = pipSnapAlgorithm;
+        mPipKeepClearAlgorithm = pipKeepClearAlgorithm;
         reloadResources(context);
         // Initialize the aspect ratio to the default aspect ratio.  Don't do this in reload
         // resources as it would clobber mAspectRatio when entering PiP from fullscreen which
@@ -129,8 +132,21 @@
         return getDefaultBounds(INVALID_SNAP_FRACTION, null /* size */);
     }
 
-    /** Returns the destination bounds to place the PIP window on entry. */
+    /**
+     * Returns the destination bounds to place the PIP window on entry.
+     * If there are any keep clear areas registered, the position will try to avoid occluding them.
+     */
     public Rect getEntryDestinationBounds() {
+        Rect entryBounds = getEntryDestinationBoundsIgnoringKeepClearAreas();
+        Rect insets = new Rect();
+        getInsetBounds(insets);
+        return mPipKeepClearAlgorithm.findUnoccludedPosition(entryBounds,
+                mPipBoundsState.getRestrictedKeepClearAreas(),
+                mPipBoundsState.getUnrestrictedKeepClearAreas(), insets);
+    }
+
+    /** Returns the destination bounds to place the PIP window on entry. */
+    public Rect getEntryDestinationBoundsIgnoringKeepClearAreas() {
         final PipBoundsState.PipReentryState reentryState = mPipBoundsState.getReentryState();
 
         final Rect destinationBounds = reentryState != null
@@ -138,9 +154,10 @@
                 : getDefaultBounds();
 
         final boolean useCurrentSize = reentryState != null && reentryState.getSize() != null;
-        return transformBoundsToAspectRatioIfValid(destinationBounds,
+        Rect aspectRatioBounds = transformBoundsToAspectRatioIfValid(destinationBounds,
                 mPipBoundsState.getAspectRatio(), false /* useCurrentMinEdgeSize */,
                 useCurrentSize);
+        return aspectRatioBounds;
     }
 
     /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java
new file mode 100644
index 0000000..e3495e1
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipKeepClearAlgorithm.java
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+import android.graphics.Rect;
+
+import java.util.Set;
+
+/**
+ * Interface for interacting with keep clear algorithm used to move PiP window out of the way of
+ * keep clear areas.
+ */
+public interface PipKeepClearAlgorithm {
+
+    /**
+     * Adjust the position of picture in picture window based on the registered keep clear areas.
+     * @param pipBoundsState state of the PiP to use for the calculations
+     * @param pipBoundsAlgorithm algorithm implementation used to get the entry destination bounds
+     * @return
+     */
+    default Rect adjust(PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) {
+        return pipBoundsState.getBounds();
+    }
+
+    /**
+     * Calculate the bounds so that none of the keep clear areas are occluded, while the bounds stay
+     * within the allowed bounds. If such position is not feasible, return original bounds.
+     * @param defaultBounds initial bounds used in the calculation
+     * @param restrictedKeepClearAreas registered restricted keep clear areas
+     * @param unrestrictedKeepClearAreas registered unrestricted keep clear areas
+     * @param allowedBounds bounds that define the allowed space for the output, result will always
+     *                      be inside those bounds
+     * @return bounds that don't cover any of the keep clear areas and are within allowed bounds
+     */
+    default Rect findUnoccludedPosition(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
+            Set<Rect> unrestrictedKeepClearAreas, Rect allowedBounds) {
+        return defaultBounds;
+    }
+}
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 b46eff6..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) {
@@ -1306,6 +1306,12 @@
             return;
         }
 
+        if (mLeash == null || !mLeash.isValid()) {
+            Log.e(TAG, String.format("scheduleFinishResizePip with null leash! mState=%d",
+                  mPipTransitionState.getTransitionState()));
+            return;
+        }
+
         finishResize(createFinishResizeSurfaceTransaction(destinationBounds), destinationBounds,
                 direction, -1);
         if (updateBoundsCallback != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
index 1a4be3b..c6b5ce9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionState.java
@@ -88,6 +88,11 @@
         return isInPip(mState);
     }
 
+    /** Returns true if activity has fully entered PiP mode. */
+    public boolean hasEnteredPip() {
+        return hasEnteredPip(mState);
+    }
+
     public void setInSwipePipToHomeTransition(boolean inSwipePipToHomeTransition) {
         mInSwipePipToHomeTransition = inSwipePipToHomeTransition;
     }
@@ -120,6 +125,11 @@
         return state >= TASK_APPEARED && state != EXITING_PIP;
     }
 
+    /** Returns true if activity has fully entered PiP mode. */
+    public static boolean hasEnteredPip(@TransitionState int state) {
+        return state == ENTERED_PIP;
+    }
+
     public interface OnPipTransitionStateChangedListener {
         void onPipTransitionStateChanged(@TransitionState int oldState,
                 @TransitionState int newState);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
new file mode 100644
index 0000000..6dd02e4
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -0,0 +1,147 @@
+/*
+ * 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.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.ArraySet;
+import android.view.Gravity;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
+
+import java.util.Set;
+
+/**
+ * Calculates the adjusted position that does not occlude keep clear areas.
+ */
+public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
+
+    protected int mKeepClearAreasPadding;
+
+    public PhonePipKeepClearAlgorithm(Context context) {
+        reloadResources(context);
+    }
+
+    private void reloadResources(Context context) {
+        final Resources res = context.getResources();
+        mKeepClearAreasPadding = res.getDimensionPixelSize(R.dimen.pip_keep_clear_areas_padding);
+    }
+
+    /**
+     * Adjusts the current position of PiP to avoid occluding keep clear areas. This will push PiP
+     * towards the closest edge and then apply calculations to avoid occluding keep clear areas.
+     */
+    public Rect adjust(PipBoundsState pipBoundsState, PipBoundsAlgorithm pipBoundsAlgorithm) {
+        Rect startingBounds = pipBoundsState.getBounds().isEmpty()
+                ? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
+                : pipBoundsState.getBounds();
+        float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
+        int verticalGravity;
+        int horizontalGravity;
+        if (snapFraction < 1.5f || snapFraction >= 3.5f) {
+            verticalGravity = Gravity.NO_GRAVITY;
+        } else {
+            verticalGravity = Gravity.BOTTOM;
+        }
+        if (snapFraction >= 0.5f && snapFraction < 2.5f) {
+            horizontalGravity = Gravity.RIGHT;
+        } else {
+            horizontalGravity = Gravity.LEFT;
+        }
+        // push the bounds based on the gravity
+        Rect insets = new Rect();
+        pipBoundsAlgorithm.getInsetBounds(insets);
+        if (pipBoundsState.isImeShowing()) {
+            insets.bottom -= pipBoundsState.getImeHeight();
+        }
+        Rect pushedBounds = new Rect(startingBounds);
+        if (verticalGravity == Gravity.BOTTOM) {
+            pushedBounds.offsetTo(pushedBounds.left,
+                    insets.bottom - pushedBounds.height());
+        }
+        if (horizontalGravity == Gravity.RIGHT) {
+            pushedBounds.offsetTo(insets.right - pushedBounds.width(), pushedBounds.top);
+        } else {
+            pushedBounds.offsetTo(insets.left, pushedBounds.top);
+        }
+        return findUnoccludedPosition(pushedBounds, pipBoundsState.getRestrictedKeepClearAreas(),
+                pipBoundsState.getUnrestrictedKeepClearAreas(), insets);
+    }
+
+    /** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
+    public Rect findUnoccludedPosition(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
+            Set<Rect> unrestrictedKeepClearAreas, Rect allowedBounds) {
+        if (restrictedKeepClearAreas.isEmpty() && unrestrictedKeepClearAreas.isEmpty()) {
+            return defaultBounds;
+        }
+        Set<Rect> keepClearAreas = new ArraySet<>();
+        if (!restrictedKeepClearAreas.isEmpty()) {
+            keepClearAreas.addAll(restrictedKeepClearAreas);
+        }
+        if (!unrestrictedKeepClearAreas.isEmpty()) {
+            keepClearAreas.addAll(unrestrictedKeepClearAreas);
+        }
+        Rect outBounds = new Rect(defaultBounds);
+        for (Rect r : keepClearAreas) {
+            Rect tmpRect = new Rect(r);
+            // add extra padding to the keep clear area
+            tmpRect.inset(-mKeepClearAreasPadding, -mKeepClearAreasPadding);
+            if (Rect.intersects(r, outBounds)) {
+                if (tryOffsetUp(outBounds, tmpRect, allowedBounds)) continue;
+                if (tryOffsetLeft(outBounds, tmpRect, allowedBounds)) continue;
+                if (tryOffsetDown(outBounds, tmpRect, allowedBounds)) continue;
+                if (tryOffsetRight(outBounds, tmpRect, allowedBounds)) continue;
+            }
+        }
+        return outBounds;
+    }
+
+    private static boolean tryOffsetLeft(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+        return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+                rectToAvoid.left - rectToMove.right, 0);
+    }
+
+    private static boolean tryOffsetRight(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+        return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+                rectToAvoid.right - rectToMove.left, 0);
+    }
+
+    private static boolean tryOffsetUp(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+        return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+                0, rectToAvoid.top - rectToMove.bottom);
+    }
+
+    private static boolean tryOffsetDown(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds) {
+        return tryOffset(rectToMove, rectToAvoid, allowedBounds,
+                0, rectToAvoid.bottom - rectToMove.top);
+    }
+
+    private static boolean tryOffset(Rect rectToMove, Rect rectToAvoid, Rect allowedBounds,
+            int dx, int dy) {
+        Rect tmp = new Rect(rectToMove);
+        tmp.offset(dx, dy);
+        if (!Rect.intersects(rectToAvoid, tmp) && allowedBounds.contains(tmp)) {
+            rectToMove.offsetTo(tmp.left, tmp.top);
+            return true;
+        }
+        return false;
+    }
+}
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 ac3407d..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
@@ -43,11 +43,13 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 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;
@@ -63,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;
@@ -79,6 +82,7 @@
 import com.android.wm.shell.pip.PipAppOpsListener;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
 import com.android.wm.shell.pip.PipMediaController;
 import com.android.wm.shell.pip.PipParamsChangedForwarder;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
@@ -110,6 +114,17 @@
         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);
+
+    @VisibleForTesting
+    void setEnablePipKeepClearAlgorithm(boolean value) {
+        mEnablePipKeepClearAlgorithm = value;
+    }
+
     private Context mContext;
     protected ShellExecutor mMainExecutor;
     private DisplayController mDisplayController;
@@ -125,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;
@@ -133,6 +149,8 @@
     private final Rect mTmpInsetBounds = new Rect();
     private final int mEnterAnimationDuration;
 
+    private final Runnable mMovePipInResponseToKeepClearAreasChangeCallback;
+
     private boolean mIsInFixedRotation;
     private PipAnimationListener mPinnedStackAnimationRecentsCallback;
 
@@ -262,7 +280,15 @@
                 public void onKeepClearAreasChanged(int displayId, Set<Rect> restricted,
                         Set<Rect> unrestricted) {
                     if (mPipBoundsState.getDisplayId() == displayId) {
-                        mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+                        if (mEnablePipKeepClearAlgorithm) {
+                            mPipBoundsState.setKeepClearAreas(restricted, unrestricted);
+
+                            mMainExecutor.removeCallbacks(
+                                    mMovePipInResponseToKeepClearAreasChangeCallback);
+                            mMainExecutor.executeDelayed(
+                                    mMovePipInResponseToKeepClearAreasChangeCallback,
+                                    PIP_KEEP_CLEAR_AREAS_DELAY);
+                        }
                     }
                 }
             };
@@ -318,6 +344,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor) {
         if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -331,7 +358,7 @@
                 pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
                 pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                oneHandedController, mainExecutor)
+                displayInsetsController, oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -354,6 +381,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor
     ) {
@@ -386,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);
     }
@@ -529,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() {
@@ -759,8 +807,16 @@
 
     private Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
             PictureInPictureParams pictureInPictureParams,
-            int launcherRotation, int shelfHeight) {
-        setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
+            int launcherRotation, Rect hotseatKeepClearArea) {
+
+        if (mEnablePipKeepClearAlgorithm) {
+            // pre-emptively add the keep clear area for Hotseat, so that it is taken into account
+            // when calculating the entry destination bounds of PiP window
+            mPipBoundsState.getRestrictedKeepClearAreas().add(hotseatKeepClearArea);
+        } else {
+            int shelfHeight = hotseatKeepClearArea.height();
+            setShelfHeightLocked(shelfHeight > 0 /* visible */, shelfHeight);
+        }
         onDisplayRotationChangedNotInPip(mContext, launcherRotation);
         final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
                 pictureInPictureParams);
@@ -1059,12 +1115,12 @@
         @Override
         public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo,
                 PictureInPictureParams pictureInPictureParams, int launcherRotation,
-                int shelfHeight) {
+                Rect keepClearArea) {
             Rect[] result = new Rect[1];
             executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome",
                     (controller) -> {
                         result[0] = controller.startSwipePipToHome(componentName, activityInfo,
-                                pictureInPictureParams, launcherRotation, shelfHeight);
+                                pictureInPictureParams, launcherRotation, keepClearArea);
                     }, true /* blocking */);
             return result[0];
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
deleted file mode 100644
index 78084fa..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithm.java
+++ /dev/null
@@ -1,97 +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.pip.phone;
-
-import android.graphics.Rect;
-import android.util.ArraySet;
-
-import com.android.wm.shell.pip.PipBoundsAlgorithm;
-import com.android.wm.shell.pip.PipBoundsState;
-
-import java.util.Set;
-
-/**
- * Calculates the adjusted position that does not occlude keep clear areas.
- */
-public class PipKeepClearAlgorithm {
-
-    /**
-     * Adjusts the current position of PiP to avoid occluding keep clear areas. If the user has
-     * moved PiP manually, the unmodified current position will be returned instead.
-     */
-    public Rect adjust(PipBoundsState boundsState, PipBoundsAlgorithm boundsAlgorithm) {
-        if (boundsState.hasUserResizedPip()) {
-            return boundsState.getBounds();
-        }
-        return adjust(boundsAlgorithm.getEntryDestinationBounds(),
-                boundsState.getRestrictedKeepClearAreas(),
-                boundsState.getUnrestrictedKeepClearAreas(), boundsState.getDisplayBounds());
-    }
-
-    /** Returns a new {@code Rect} that does not occlude the provided keep clear areas. */
-    public Rect adjust(Rect defaultBounds, Set<Rect> restrictedKeepClearAreas,
-            Set<Rect> unrestrictedKeepClearAreas, Rect displayBounds) {
-        if (restrictedKeepClearAreas.isEmpty()) {
-            return defaultBounds;
-        }
-        Set<Rect> keepClearAreas = new ArraySet<>();
-        if (!restrictedKeepClearAreas.isEmpty()) {
-            keepClearAreas.addAll(restrictedKeepClearAreas);
-        }
-        Rect outBounds = new Rect(defaultBounds);
-        for (Rect r : keepClearAreas) {
-            if (Rect.intersects(r, outBounds)) {
-                if (tryOffsetUp(outBounds, r, displayBounds)) continue;
-                if (tryOffsetLeft(outBounds, r, displayBounds)) continue;
-                if (tryOffsetDown(outBounds, r, displayBounds)) continue;
-                if (tryOffsetRight(outBounds, r, displayBounds)) continue;
-            }
-        }
-        return outBounds;
-    }
-
-    private boolean tryOffsetLeft(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
-        return tryOffset(rectToMove, rectToAvoid, displayBounds,
-                rectToAvoid.left - rectToMove.right, 0);
-    }
-
-    private boolean tryOffsetRight(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
-        return tryOffset(rectToMove, rectToAvoid, displayBounds,
-                rectToAvoid.right - rectToMove.left, 0);
-    }
-
-    private boolean tryOffsetUp(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
-        return tryOffset(rectToMove, rectToAvoid, displayBounds,
-                0, rectToAvoid.top - rectToMove.bottom);
-    }
-
-    private boolean tryOffsetDown(Rect rectToMove, Rect rectToAvoid, Rect displayBounds) {
-        return tryOffset(rectToMove, rectToAvoid, displayBounds,
-                0, rectToAvoid.bottom - rectToMove.top);
-    }
-
-    private boolean tryOffset(Rect rectToMove, Rect rectToAvoid, Rect displayBounds,
-            int dx, int dy) {
-        Rect tmp = new Rect(rectToMove);
-        tmp.offset(dx, dy);
-        if (!Rect.intersects(rectToAvoid, tmp) && displayBounds.contains(tmp)) {
-            rectToMove.offsetTo(tmp.left, tmp.top);
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 1958157..979b7c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -207,6 +207,9 @@
             }
         });
 
+        // this disables the ripples
+        mEnterSplitButton.setEnabled(false);
+
         findViewById(R.id.resize_handle).setAlpha(0);
 
         mActionsGroup = findViewById(R.id.actions_group);
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
 [email protected]
[email protected]
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
index 815f3dd..a4b7033 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsAlgorithm.java
@@ -38,6 +38,7 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.tv.TvPipKeepClearAlgorithm.Placement;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -48,11 +49,10 @@
  * Contains pip bounds calculations that are specific to TV.
  */
 public class TvPipBoundsAlgorithm extends PipBoundsAlgorithm {
-
     private static final String TAG = TvPipBoundsAlgorithm.class.getSimpleName();
-    private static final boolean DEBUG = TvPipController.DEBUG;
 
-    private final @NonNull TvPipBoundsState mTvPipBoundsState;
+    @NonNull
+    private final TvPipBoundsState mTvPipBoundsState;
 
     private int mFixedExpandedHeightInPx;
     private int mFixedExpandedWidthInPx;
@@ -62,7 +62,8 @@
     public TvPipBoundsAlgorithm(Context context,
             @NonNull TvPipBoundsState tvPipBoundsState,
             @NonNull PipSnapAlgorithm pipSnapAlgorithm) {
-        super(context, tvPipBoundsState, pipSnapAlgorithm);
+        super(context, tvPipBoundsState, pipSnapAlgorithm,
+                new PipKeepClearAlgorithm() {});
         this.mTvPipBoundsState = tvPipBoundsState;
         this.mKeepClearAlgorithm = new TvPipKeepClearAlgorithm();
         reloadResources(context);
@@ -89,10 +90,9 @@
     /** Returns the destination bounds to place the PIP window on entry. */
     @Override
     public Rect getEntryDestinationBounds() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: getEntryDestinationBounds()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: getEntryDestinationBounds()", TAG);
+
         updateExpandedPipSize();
         final boolean isPipExpanded = mTvPipBoundsState.isTvExpandedPipSupported()
                 && mTvPipBoundsState.getDesiredTvExpandedAspectRatio() != 0
@@ -107,10 +107,8 @@
     /** Returns the current bounds adjusted to the new aspect ratio, if valid. */
     @Override
     public Rect getAdjustedDestinationBounds(Rect currentBounds, float newAspectRatio) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: getAdjustedDestinationBounds: %f", TAG, newAspectRatio);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: getAdjustedDestinationBounds: %f", TAG, newAspectRatio);
         return adjustBoundsForTemporaryDecor(getTvPipPlacement().getBounds());
     }
 
@@ -154,24 +152,22 @@
                 restrictedKeepClearAreas,
                 unrestrictedKeepClearAreas);
 
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: screenSize: %s", TAG, screenSize);
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: stashOffset: %d", TAG, mTvPipBoundsState.getStashOffset());
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: insetBounds: %s", TAG, insetBounds.toShortString());
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: pipSize: %s", TAG, pipSize);
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: gravity: %s", TAG, Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: restrictedKeepClearAreas: %s", TAG, restrictedKeepClearAreas);
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: unrestrictedKeepClearAreas: %s", TAG, unrestrictedKeepClearAreas);
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: placement: %s", TAG, placement);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: screenSize: %s", TAG, screenSize);
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: stashOffset: %d", TAG, mTvPipBoundsState.getStashOffset());
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: insetBounds: %s", TAG, insetBounds.toShortString());
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: pipSize: %s", TAG, pipSize);
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: gravity: %s", TAG, Gravity.toString(mTvPipBoundsState.getTvPipGravity()));
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: restrictedKeepClearAreas: %s", TAG, restrictedKeepClearAreas);
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: unrestrictedKeepClearAreas: %s", TAG, unrestrictedKeepClearAreas);
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: placement: %s", TAG, placement);
 
         return placement;
     }
@@ -180,13 +176,11 @@
      * @return previous gravity if it is to be saved, or {@link Gravity#NO_GRAVITY} if not.
      */
     int updateGravityOnExpandToggled(int previousGravity, boolean expanding) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: updateGravityOnExpandToggled(), expanding: %b"
-                    + ", mOrientation: %d, previous gravity: %s",
-                    TAG, expanding, mTvPipBoundsState.getTvFixedPipOrientation(),
-                    Gravity.toString(previousGravity));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: updateGravityOnExpandToggled(), expanding: %b"
+                        + ", mOrientation: %d, previous gravity: %s",
+                TAG, expanding, mTvPipBoundsState.getTvFixedPipOrientation(),
+                Gravity.toString(previousGravity));
 
         if (!mTvPipBoundsState.isTvExpandedPipSupported()) {
             return Gravity.NO_GRAVITY;
@@ -237,10 +231,8 @@
             }
         }
         mTvPipBoundsState.setTvPipGravity(updatedGravity);
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
 
         return gravityToSave;
     }
@@ -249,10 +241,8 @@
      * @return true if gravity changed
      */
     boolean updateGravity(int keycode) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: updateGravity, keycode: %d", TAG, keycode);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: updateGravity, keycode: %d", TAG, keycode);
 
         // Check if position change is valid
         if (mTvPipBoundsState.isTvPipExpanded()) {
@@ -309,10 +299,8 @@
 
         if (updatedGravity != currentGravity) {
             mTvPipBoundsState.setTvPipGravity(updatedGravity);
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: new gravity: %s", TAG, Gravity.toString(updatedGravity));
             return true;
         }
         return false;
@@ -343,8 +331,8 @@
         final Size expandedSize;
         if (expandedRatio == 0) {
             ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                       "%s: updateExpandedPipSize(): Expanded mode aspect ratio"
-                               + " of 0 not supported", TAG);
+                    "%s: updateExpandedPipSize(): Expanded mode aspect ratio"
+                            + " of 0 not supported", TAG);
             return;
         } else if (expandedRatio < 1) {
             // vertical
@@ -356,16 +344,12 @@
                 float aspectRatioHeight = mFixedExpandedWidthInPx / expandedRatio;
 
                 if (maxHeight > aspectRatioHeight) {
-                    if (DEBUG) {
-                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                "%s: Accommodate aspect ratio", TAG);
-                    }
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: Accommodate aspect ratio", TAG);
                     expandedSize = new Size(mFixedExpandedWidthInPx, (int) aspectRatioHeight);
                 } else {
-                    if (DEBUG) {
-                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                "%s: Aspect ratio is too extreme, use max size", TAG);
-                    }
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: Aspect ratio is too extreme, use max size", TAG);
                     expandedSize = new Size(mFixedExpandedWidthInPx, maxHeight);
                 }
             }
@@ -378,26 +362,20 @@
                         - pipDecorations.left - pipDecorations.right;
                 float aspectRatioWidth = mFixedExpandedHeightInPx * expandedRatio;
                 if (maxWidth > aspectRatioWidth) {
-                    if (DEBUG) {
-                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                "%s: Accommodate aspect ratio", TAG);
-                    }
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: Accommodate aspect ratio", TAG);
                     expandedSize = new Size((int) aspectRatioWidth, mFixedExpandedHeightInPx);
                 } else {
-                    if (DEBUG) {
-                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                "%s: Aspect ratio is too extreme, use max size", TAG);
-                    }
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: Aspect ratio is too extreme, use max size", TAG);
                     expandedSize = new Size(maxWidth, mFixedExpandedHeightInPx);
                 }
             }
         }
 
         mTvPipBoundsState.setTvExpandedSize(expandedSize);
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                       "%s: updateExpandedPipSize(): expanded size, width: %d, height: %d",
-                    TAG, expandedSize.getWidth(), expandedSize.getHeight());
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: updateExpandedPipSize(): expanded size, width: %d, height: %d",
+                TAG, expandedSize.getWidth(), expandedSize.getHeight());
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
index b212ea9..b189163 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipBoundsController.java
@@ -39,7 +39,6 @@
  * Manages debouncing of PiP movements and scheduling of unstashing.
  */
 public class TvPipBoundsController {
-    private static final boolean DEBUG = false;
     private static final String TAG = "TvPipBoundsController";
 
     /**
@@ -133,11 +132,9 @@
 
     private void schedulePinnedStackPlacement(@NonNull final Placement placement,
             int animationDuration) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: schedulePinnedStackPlacement() - pip bounds: %s",
-                    TAG, placement.getBounds().toShortString());
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: schedulePinnedStackPlacement() - pip bounds: %s",
+                TAG, placement.getBounds().toShortString());
 
         if (mPendingPlacement != null && Objects.equals(mPendingPlacement.getBounds(),
                 placement.getBounds())) {
@@ -171,10 +168,8 @@
     }
 
     private void applyPendingPlacement() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: applyPendingPlacement()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: applyPendingPlacement()", TAG);
         if (mPendingPlacement != null) {
             applyPlacement(mPendingPlacement, mPendingStash, mPendingPlacementAnimationDuration);
             mPendingStash = false;
@@ -226,10 +221,8 @@
         }
 
         mPipTargetBounds = bounds;
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: movePipTo() - new pip bounds: %s", TAG, bounds.toShortString());
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: movePipTo() - new pip bounds: %s", TAG, bounds.toShortString());
 
         if (mListener != null) {
             mListener.onPipTargetBoundsChange(bounds, animationDuration);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
index 4e1b046..85a544b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java
@@ -70,7 +70,6 @@
         TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener,
         ConfigurationChangeListener, UserChangeListener {
     private static final String TAG = "TvPipController";
-    static final boolean DEBUG = false;
 
     private static final int NONEXISTENT_TASK_ID = -1;
 
@@ -80,7 +79,8 @@
             STATE_PIP,
             STATE_PIP_MENU,
     })
-    public @interface State {}
+    public @interface State {
+    }
 
     /**
      * State when there is no applications in Pip.
@@ -117,7 +117,8 @@
     private final ShellExecutor mMainExecutor;
     private final TvPipImpl mImpl = new TvPipImpl();
 
-    private @State int mState = STATE_NO_PIP;
+    @State
+    private int mState = STATE_NO_PIP;
     private int mPreviousGravity = TvPipBoundsState.DEFAULT_TV_GRAVITY;
     private int mPinnedTaskId = NONEXISTENT_TASK_ID;
 
@@ -236,16 +237,12 @@
 
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onConfigurationChanged(), state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onConfigurationChanged(), state=%s", TAG, stateToName(mState));
 
         if (isPipShown()) {
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s:  > closing Pip.", TAG);
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s:  > closing Pip.", TAG);
             closePip();
         }
 
@@ -268,16 +265,12 @@
      */
     @Override
     public void showPictureInPictureMenu() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: showPictureInPictureMenu(), state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: showPictureInPictureMenu(), state=%s", TAG, stateToName(mState));
 
         if (mState == STATE_NO_PIP) {
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s:  > cannot open Menu from the current state.", TAG);
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s:  > cannot open Menu from the current state.", TAG);
             return;
         }
 
@@ -288,10 +281,8 @@
 
     @Override
     public void onMenuClosed() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: closeMenu(), state before=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: closeMenu(), state before=%s", TAG, stateToName(mState));
         setState(STATE_PIP);
         updatePinnedStackBounds();
     }
@@ -306,10 +297,8 @@
      */
     @Override
     public void movePipToFullscreen() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: movePipToFullscreen(), state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: movePipToFullscreen(), state=%s", TAG, stateToName(mState));
 
         mPipTaskOrganizer.exitPip(mResizeAnimationDuration, false /* requestEnterSplit */);
         onPipDisappeared();
@@ -317,10 +306,8 @@
 
     @Override
     public void togglePipExpansion() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: togglePipExpansion()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: togglePipExpansion()", TAG);
         boolean expanding = !mTvPipBoundsState.isTvPipExpanded();
         int saveGravity = mTvPipBoundsAlgorithm
                 .updateGravityOnExpandToggled(mPreviousGravity, expanding);
@@ -347,10 +334,8 @@
             mPreviousGravity = Gravity.NO_GRAVITY;
             updatePinnedStackBounds();
         } else {
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s: Position hasn't changed", TAG);
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: Position hasn't changed", TAG);
         }
     }
 
@@ -403,11 +388,9 @@
      */
     @Override
     public void closePip() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: closePip(), state=%s, loseAction=%s", TAG, stateToName(mState),
-                    mCloseAction);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: closePip(), state=%s, loseAction=%s", TAG, stateToName(mState),
+                mCloseAction);
 
         if (mCloseAction != null) {
             try {
@@ -443,10 +426,8 @@
 
     private void checkIfPinnedTaskAppeared() {
         final TaskInfo pinnedTask = getPinnedTaskInfo();
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: checkIfPinnedTaskAppeared(), task=%s", TAG, pinnedTask);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: checkIfPinnedTaskAppeared(), task=%s", TAG, pinnedTask);
         if (pinnedTask == null || pinnedTask.topActivity == null) return;
         mPinnedTaskId = pinnedTask.taskId;
 
@@ -455,10 +436,8 @@
     }
 
     private void checkIfPinnedTaskIsGone() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onTaskStackChanged()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onTaskStackChanged()", TAG);
 
         if (isPipShown() && getPinnedTaskInfo() == null) {
             ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -468,10 +447,8 @@
     }
 
     private void onPipDisappeared() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onPipDisappeared() state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onPipDisappeared() state=%s", TAG, stateToName(mState));
 
         mPipNotificationController.dismiss();
         mTvPipMenuController.closeMenu();
@@ -483,19 +460,15 @@
 
     @Override
     public void onPipTransitionStarted(int direction, Rect pipBounds) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onPipTransition_Started(), state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onPipTransition_Started(), state=%s", TAG, stateToName(mState));
         mTvPipMenuController.notifyPipAnimating(true);
     }
 
     @Override
     public void onPipTransitionCanceled(int direction) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onPipTransition_Canceled(), state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onPipTransition_Canceled(), state=%s", TAG, stateToName(mState));
         mTvPipMenuController.notifyPipAnimating(false);
     }
 
@@ -504,19 +477,15 @@
         if (PipAnimationController.isInPipDirection(direction) && mState == STATE_NO_PIP) {
             setState(STATE_PIP);
         }
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onPipTransition_Finished(), state=%s", TAG, stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onPipTransition_Finished(), state=%s", TAG, stateToName(mState));
         mTvPipMenuController.notifyPipAnimating(false);
     }
 
     private void setState(@State int state) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: setState(), state=%s, prev=%s",
-                    TAG, stateToName(state), stateToName(mState));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: setState(), state=%s, prev=%s",
+                TAG, stateToName(state), stateToName(mState));
         mState = state;
     }
 
@@ -550,11 +519,8 @@
             public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
                     boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
                 if (task.getWindowingMode() == WINDOWING_MODE_PINNED) {
-                    if (DEBUG) {
-                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                "%s: onPinnedActivityRestartAttempt()", TAG);
-                    }
-
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: onPinnedActivityRestartAttempt()", TAG);
                     // If the "Pip-ed" Activity is launched again by Launcher or intent, make it
                     // fullscreen.
                     movePipToFullscreen();
@@ -569,7 +535,7 @@
             public void onActionsChanged(List<RemoteAction> actions,
                     RemoteAction closeAction) {
                 ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                            "%s: onActionsChanged()", TAG);
+                        "%s: onActionsChanged()", TAG);
 
                 mTvPipMenuController.setAppActions(actions, closeAction);
                 mCloseAction = closeAction;
@@ -578,7 +544,7 @@
             @Override
             public void onAspectRatioChanged(float ratio) {
                 ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                            "%s: onAspectRatioChanged: %f", TAG, ratio);
+                        "%s: onAspectRatioChanged: %f", TAG, ratio);
 
                 mTvPipBoundsState.setAspectRatio(ratio);
                 if (!mTvPipBoundsState.isTvPipExpanded()) {
@@ -589,7 +555,7 @@
             @Override
             public void onExpandedAspectRatioChanged(float ratio) {
                 ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                            "%s: onExpandedAspectRatioChanged: %f", TAG, ratio);
+                        "%s: onExpandedAspectRatioChanged: %f", TAG, ratio);
 
                 mTvPipBoundsState.setDesiredTvExpandedAspectRatio(ratio, false);
                 mTvPipMenuController.updateExpansionState();
@@ -635,11 +601,9 @@
             wmShell.addPinnedStackListener(new PinnedStackListenerForwarder.PinnedTaskListener() {
                 @Override
                 public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-                    if (DEBUG) {
-                        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                                "%s: onImeVisibilityChanged(), visible=%b, height=%d",
-                                TAG, imeVisible, imeHeight);
-                    }
+                    ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                            "%s: onImeVisibilityChanged(), visible=%b, height=%d",
+                            TAG, imeVisible, imeHeight);
 
                     if (imeVisible == mTvPipBoundsState.isImeShowing()
                             && (!imeVisible || imeHeight == mTvPipBoundsState.getImeHeight())) {
@@ -661,17 +625,13 @@
     }
 
     private static TaskInfo getPinnedTaskInfo() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: getPinnedTaskInfo()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: getPinnedTaskInfo()", TAG);
         try {
             final TaskInfo taskInfo = ActivityTaskManager.getService().getRootTaskInfo(
                     WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s: taskInfo=%s", TAG, taskInfo);
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: taskInfo=%s", TAG, taskInfo);
             return taskInfo;
         } catch (RemoteException e) {
             ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -681,10 +641,8 @@
     }
 
     private static void removeTask(int taskId) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: removeTask(), taskId=%d", TAG, taskId);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: removeTask(), taskId=%d", TAG, taskId);
         try {
             ActivityTaskManager.getService().removeTask(taskId);
         } catch (Exception e) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index a4e9062..176fdfe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -54,7 +54,6 @@
  */
 public class TvPipMenuController implements PipMenuController, TvPipMenuView.Listener {
     private static final String TAG = "TvPipMenuController";
-    private static final boolean DEBUG = TvPipController.DEBUG;
     private static final String BACKGROUND_WINDOW_TITLE = "PipBackgroundView";
 
     private final Context mContext;
@@ -119,10 +118,8 @@
     }
 
     void setDelegate(Delegate delegate) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: setDelegate(), delegate=%s", TAG, delegate);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: setDelegate(), delegate=%s", TAG, delegate);
         if (mDelegate != null) {
             throw new IllegalStateException(
                     "The delegate has already been set and should not change.");
@@ -145,10 +142,8 @@
     }
 
     private void attachPipMenu() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: attachPipMenu()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: attachPipMenu()", TAG);
 
         if (mPipMenuView != null) {
             detachPipMenu();
@@ -158,7 +153,7 @@
         attachPipMenuView();
 
         mTvPipBoundsState.setPipMenuPermanentDecorInsets(Insets.of(-mPipMenuBorderWidth,
-                    -mPipMenuBorderWidth, -mPipMenuBorderWidth, -mPipMenuBorderWidth));
+                -mPipMenuBorderWidth, -mPipMenuBorderWidth, -mPipMenuBorderWidth));
         mTvPipBoundsState.setPipMenuTemporaryDecorInsets(Insets.of(0, 0, 0, -mPipEduTextHeight));
         mMainHandler.postDelayed(mCloseEduTextRunnable, mPipEduTextShowDurationMs);
     }
@@ -180,15 +175,15 @@
 
     private void setUpViewSurfaceZOrder(View v, int zOrderRelativeToPip) {
         v.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
-                @Override
-                public void onViewAttachedToWindow(View v) {
-                    v.getViewRootImpl().addSurfaceChangedCallback(
-                            new PipMenuSurfaceChangedCallback(v, zOrderRelativeToPip));
-                }
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                v.getViewRootImpl().addSurfaceChangedCallback(
+                        new PipMenuSurfaceChangedCallback(v, zOrderRelativeToPip));
+            }
 
-                @Override
-                public void onViewDetachedFromWindow(View v) {
-                }
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+            }
         });
     }
 
@@ -205,10 +200,8 @@
     }
 
     void showMovementMenuOnly() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: showMovementMenuOnly()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: showMovementMenuOnly()", TAG);
         setInMoveMode(true);
         mCloseAfterExitMoveMenu = true;
         showMenuInternal();
@@ -216,9 +209,7 @@
 
     @Override
     public void showMenu() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMenu()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMenu()", TAG);
         setInMoveMode(false);
         mCloseAfterExitMoveMenu = false;
         showMenuInternal();
@@ -274,15 +265,12 @@
     }
 
     void closeMenu() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: closeMenu()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: closeMenu()", TAG);
 
         if (mPipMenuView == null) {
             return;
         }
-
         mPipMenuView.hideAllUserControls();
         grantPipMenuFocus(false);
         mDelegate.onMenuClosed();
@@ -296,7 +284,6 @@
         if (mInMoveMode == moveMode) {
             return;
         }
-
         mInMoveMode = moveMode;
         if (mDelegate != null) {
             mDelegate.onInMoveModeChanged();
@@ -305,22 +292,19 @@
 
     @Override
     public void onEnterMoveMode() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onEnterMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
-                    mCloseAfterExitMoveMenu);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onEnterMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
+                mCloseAfterExitMoveMenu);
         setInMoveMode(true);
         mPipMenuView.showMoveMenu(mDelegate.getPipGravity());
     }
 
     @Override
     public boolean onExitMoveMode() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onExitMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
-                    mCloseAfterExitMoveMenu);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onExitMoveMode - %b, close when exiting move menu: %b", TAG, mInMoveMode,
+                mCloseAfterExitMoveMenu);
+
         if (mCloseAfterExitMoveMenu) {
             setInMoveMode(false);
             mCloseAfterExitMoveMenu = false;
@@ -337,10 +321,8 @@
 
     @Override
     public boolean onPipMovement(int keycode) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onPipMovement - %b", TAG, mInMoveMode);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onPipMovement - %b", TAG, mInMoveMode);
         if (mInMoveMode) {
             mDelegate.movePip(keycode);
         }
@@ -357,18 +339,14 @@
 
     @Override
     public void setAppActions(List<RemoteAction> actions, RemoteAction closeAction) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: setAppActions()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: setAppActions()", TAG);
         updateAdditionalActionsList(mAppActions, actions, closeAction);
     }
 
     private void onMediaActionsChanged(List<RemoteAction> actions) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: onMediaActionsChanged()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: onMediaActionsChanged()", TAG);
 
         // Hide disabled actions.
         List<RemoteAction> enabledActions = new ArrayList<>();
@@ -420,10 +398,8 @@
     public void resizePipMenu(@Nullable SurfaceControl pipLeash,
             @Nullable SurfaceControl.Transaction t,
             Rect destinationBounds) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString());
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: resizePipMenu: %s", TAG, destinationBounds.toShortString());
         if (destinationBounds.isEmpty()) {
             return;
         }
@@ -437,14 +413,14 @@
         final SurfaceControl frontSurface = getSurfaceControl(mPipMenuView);
         final SyncRtSurfaceTransactionApplier.SurfaceParams frontParams =
                 new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(frontSurface)
-                .withWindowCrop(menuBounds)
-                .build();
+                        .withWindowCrop(menuBounds)
+                        .build();
 
         final SurfaceControl backSurface = getSurfaceControl(mPipBackgroundView);
         final SyncRtSurfaceTransactionApplier.SurfaceParams backParams =
                 new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(backSurface)
-                .withWindowCrop(menuBounds)
-                .build();
+                        .withWindowCrop(menuBounds)
+                        .build();
 
         // TODO(b/226580399): switch to using SurfaceSyncer (see b/200284684) to synchronize the
         // animations of the pip surface with the content of the front and back menu surfaces
@@ -467,13 +443,11 @@
     @Override
     public void movePipMenu(SurfaceControl pipLeash, SurfaceControl.Transaction transaction,
             Rect pipDestBounds) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString());
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: movePipMenu: %s", TAG, pipDestBounds.toShortString());
 
         if (pipDestBounds.isEmpty()) {
-            if (transaction == null && DEBUG) {
+            if (transaction == null) {
                 ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                         "%s: no transaction given", TAG);
             }
@@ -489,16 +463,12 @@
         // resizing and the PiP menu is also resized. We then want to do a scale from the current
         // new menu bounds.
         if (pipLeash != null && transaction != null) {
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s: tmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG);
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: tmpSourceBounds based on mPipMenuView.getBoundsOnScreen()", TAG);
             mPipMenuView.getBoundsOnScreen(tmpSourceBounds);
         } else {
-            if (DEBUG) {
-                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                        "%s: tmpSourceBounds based on menu width and height", TAG);
-            }
+            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                    "%s: tmpSourceBounds based on menu width and height", TAG);
             tmpSourceBounds.set(0, 0, menuDestBounds.width(), menuDestBounds.height());
         }
 
@@ -524,8 +494,8 @@
         if (pipLeash != null && transaction != null) {
             final SyncRtSurfaceTransactionApplier.SurfaceParams pipParams =
                     new SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(pipLeash)
-                    .withMergeTransaction(transaction)
-                    .build();
+                            .withMergeTransaction(transaction)
+                            .build();
             mApplier.scheduleApply(frontParams, pipParams);
         } else {
             mApplier.scheduleApply(frontParams);
@@ -567,10 +537,8 @@
     @Override
     public void updateMenuBounds(Rect destinationBounds) {
         final Rect menuBounds = calculateMenuSurfaceBounds(destinationBounds);
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: updateMenuBounds: %s", TAG, menuBounds.toShortString());
         mSystemWindows.updateViewLayout(mPipBackgroundView,
                 getPipMenuLayoutParams(mContext, BACKGROUND_WINDOW_TITLE, menuBounds.width(),
                         menuBounds.height()));
@@ -629,10 +597,8 @@
     }
 
     private void grantPipMenuFocus(boolean grantFocus) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: grantWindowFocus(%b)", TAG, grantFocus);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: grantWindowFocus(%b)", TAG, grantFocus);
 
         try {
             WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null /* window */,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
index 97e017a..9cd05b0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuView.java
@@ -71,7 +71,6 @@
  */
 public class TvPipMenuView extends FrameLayout implements View.OnClickListener {
     private static final String TAG = "TvPipMenuView";
-    private static final boolean DEBUG = TvPipController.DEBUG;
 
     private static final int FIRST_CUSTOM_ACTION_POSITION = 3;
 
@@ -448,10 +447,8 @@
     }
 
     void setIsExpanded(boolean expanded) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: setIsExpanded, expanded: %b", TAG, expanded);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: setIsExpanded, expanded: %b", TAG, expanded);
         mExpandButton.setImageResource(
                 expanded ? R.drawable.pip_ic_collapse : R.drawable.pip_ic_expand);
         mExpandButton.setTextAndDescription(
@@ -462,9 +459,7 @@
      * @param gravity for the arrow hints
      */
     void showMoveMenu(int gravity) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: showMoveMenu()", TAG);
         mButtonMenuIsVisible = false;
         mMoveMenuIsVisible = true;
         showButtonsMenu(false);
@@ -476,11 +471,8 @@
     }
 
     void showButtonsMenu() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: showButtonsMenu()", TAG);
-        }
-
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: showButtonsMenu()", TAG);
         mButtonMenuIsVisible = true;
         mMoveMenuIsVisible = false;
         showButtonsMenu(true);
@@ -553,10 +545,8 @@
      */
     void setAdditionalActions(List<RemoteAction> actions, RemoteAction closeAction,
             Handler mainHandler) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: setAdditionalActions()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: setAdditionalActions()", TAG);
 
         // Replace system close action with custom close action if available
         if (closeAction != null) {
@@ -707,10 +697,8 @@
      * Shows user hints for moving the PiP, e.g. arrows.
      */
     public void showMovementHints(int gravity) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: showMovementHints(), position: %s", TAG, Gravity.toString(gravity));
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: showMovementHints(), position: %s", TAG, Gravity.toString(gravity));
 
         animateAlphaTo(checkGravity(gravity, Gravity.BOTTOM) ? 1f : 0f, mArrowUp);
         animateAlphaTo(checkGravity(gravity, Gravity.TOP) ? 1f : 0f, mArrowDown);
@@ -752,10 +740,9 @@
      * Hides user hints for moving the PiP, e.g. arrows.
      */
     public void hideMovementHints() {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: hideMovementHints()", TAG);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: hideMovementHints()", TAG);
+
         animateAlphaTo(0, mArrowUp);
         animateAlphaTo(0, mArrowRight);
         animateAlphaTo(0, mArrowDown);
@@ -767,10 +754,8 @@
      * Show or hide the pip buttons menu.
      */
     public void showButtonsMenu(boolean show) {
-        if (DEBUG) {
-            ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
-                    "%s: showUserActions: %b", TAG, show);
-        }
+        ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                "%s: showUserActions: %b", TAG, show);
         if (show) {
             mActionButtonsContainer.setVisibility(VISIBLE);
             refocusPreviousButton();
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 51921e7..3714fe7 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
@@ -18,6 +18,7 @@
 
 import android.app.PendingIntent;
 import android.content.Intent;
+import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.view.RemoteAnimationAdapter;
@@ -89,7 +90,7 @@
             float splitRatio, in RemoteAnimationAdapter adapter) = 11;
 
     /**
-     * Start a pair of intent and task using legacy transition system.
+     * 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,
@@ -108,4 +109,11 @@
      * does not expect split to currently be running.
      */
     RemoteAnimationTarget[] onStartingSplitLegacy(in RemoteAnimationTarget[] appTargets) = 14;
+
+    /**
+     * Starts a pair of shortcut and task using legacy transition system.
+     */
+    oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo, int taskId,
+            in Bundle mainOptions, in Bundle sideOptions, int sidePosition, float splitRatio,
+            in RemoteAnimationAdapter adapter) = 15;
 }
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 2117b69..9206afb 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
@@ -40,6 +40,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -146,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;
@@ -185,7 +185,6 @@
         mDragAndDropController = dragAndDropController;
         mTransitions = transitions;
         mTransactionPool = transactionPool;
-        mLogger = new SplitscreenEventLogger();
         mIconProvider = iconProvider;
         mRecentTasksOptional = recentTasks;
         mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
@@ -212,14 +211,18 @@
         mShellController.addKeyguardChangeListener(this);
         if (mStageCoordinator == null) {
             // TODO: Multi-display
-            mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
-                    mTaskOrganizer, mDisplayController, mDisplayImeController,
-                    mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
-                    mIconProvider, mMainExecutor, mRecentTasksOptional);
+            mStageCoordinator = createStageCoordinator();
         }
         mDragAndDropController.setSplitScreenController(this);
     }
 
+    protected StageCoordinator createStageCoordinator() {
+        return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
+                mTaskOrganizer, mDisplayController, mDisplayImeController,
+                mDisplayInsetsController, mTransitions, mTransactionPool,
+                mIconProvider, mMainExecutor, mRecentTasksOptional);
+    }
+
     @Override
     public Context getContext() {
         return mContext;
@@ -788,6 +791,17 @@
         }
 
         @Override
+        public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
+                int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
+                @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
+            executeRemoteCallWithTaskPermission(mController,
+                    "startShortcutAndTaskWithLegacyTransition", (controller) ->
+                            controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition(
+                                    shortcutInfo, taskId, mainOptions, sideOptions, sidePosition,
+                                    splitRatio, adapter));
+        }
+
+        @Override
         public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
                 int sideTaskId, @Nullable Bundle sideOptions,
                 @SplitPosition int sidePosition, float splitRatio,
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 7e83d2f..8ed16ce 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
@@ -25,6 +25,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -68,11 +69,12 @@
 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;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ShortcutInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.hardware.devicestate.DeviceStateManager;
@@ -80,11 +82,11 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 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;
@@ -244,18 +246,18 @@
         }
     };
 
-    StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
+    protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
             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;
 
@@ -299,7 +301,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;
@@ -314,7 +316,7 @@
         mSplitLayout = splitLayout;
         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                 this::onTransitionAnimationComplete, this);
-        mLogger = logger;
+        mLogger = new SplitscreenEventLogger();
         mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
         mDisplayController.addDisplayWindowListener(this);
@@ -488,13 +490,6 @@
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         options = resolveStartStage(STAGE_TYPE_UNDEFINED, position, options, wct);
 
-        // If split still not active, apply windows bounds first to avoid surface reset to
-        // wrong pos by SurfaceAnimator from wms.
-        // TODO(b/223325631): check  is it still necessary after improve enter transition done.
-        if (!mMainStage.isActive()) {
-            updateWindowBounds(mSplitLayout, wct);
-        }
-
         wct.sendPendingIntent(intent, fillInIntent, options);
         mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
     }
@@ -519,6 +514,7 @@
         mSplitLayout.setDivideRatio(splitRatio);
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
+        wct.setForceTranslucent(mRootTaskInfo.token, false);
 
         // Make sure the launch options will put tasks in the corresponding split roots
         addActivityOptions(mainOptions, mMainStage);
@@ -536,132 +532,136 @@
     void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
             int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
             float splitRatio, RemoteAnimationAdapter adapter) {
-        startWithLegacyTransition(mainTaskId, sideTaskId, null /* pendingIntent */,
-                null /* fillInIntent */, mainOptions, sideOptions, sidePosition, splitRatio,
-                adapter);
+        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);
     }
 
     /** 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) {
-        startWithLegacyTransition(taskId, INVALID_TASK_ID, pendingIntent, fillInIntent,
-                mainOptions, sideOptions, sidePosition, splitRatio, adapter);
+        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);
     }
 
-    private void startWithLegacyTransition(int mainTaskId, int sideTaskId,
-            @Nullable PendingIntent pendingIntent, @Nullable Intent fillInIntent,
-            @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
+    void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
+            int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
             @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter) {
-        final boolean withIntent = pendingIntent != null && fillInIntent != null;
+        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);
+    }
+
+    private void startWithLegacyTransition(WindowContainerTransaction sideWct, int mainTaskId,
+            @Nullable Bundle mainOptions, @SplitPosition int sidePosition, float splitRatio,
+            RemoteAnimationAdapter adapter) {
         // Init divider first to make divider leash for remote animation target.
         mSplitLayout.init();
+        mSplitLayout.setDivideRatio(splitRatio);
+
         // Set false to avoid record new bounds with old task still on top;
         mShouldUpdateRecents = false;
         mIsDividerRemoteAnimating = true;
-        final WindowContainerTransaction wct = new WindowContainerTransaction();
-        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
-        prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
-        prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
-        // Need to add another wrapper here in shell so that we can inject the divider bar
-        // and also manage the process elevation via setRunningRemote
-        IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
+
+        LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
             @Override
-            public void onAnimationStart(@WindowManager.TransitionOldType int transit,
-                    RemoteAnimationTarget[] apps,
-                    RemoteAnimationTarget[] wallpapers,
-                    RemoteAnimationTarget[] nonApps,
-                    final IRemoteAnimationFinishedCallback finishedCallback) {
-                RemoteAnimationTarget[] augmentedNonApps =
-                        new RemoteAnimationTarget[nonApps.length + 1];
-                for (int i = 0; i < nonApps.length; ++i) {
-                    augmentedNonApps[i] = nonApps[i];
+            public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+                    RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+                    IRemoteAnimationFinishedCallback finishedCallback,
+                    SurfaceControl.Transaction t) {
+                if (apps == null || apps.length == 0) {
+                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+                    setDividerVisibility(true, t);
+                    t.apply();
+                    onRemoteAnimationFinished(apps);
+                    try {
+                        adapter.getRunner().onAnimationCancelled(mKeyguardShowing);
+                    } catch (RemoteException e) {
+                        Slog.e(TAG, "Error starting remote animation", e);
+                    }
+                    return;
                 }
-                augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
+
+                // Wrap the divider bar into non-apps target to animate together.
+                nonApps = ArrayUtils.appendElement(RemoteAnimationTarget.class, nonApps,
+                        getDividerBarLegacyTarget());
+
+                updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+                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();
 
                 IRemoteAnimationFinishedCallback wrapCallback =
                         new IRemoteAnimationFinishedCallback.Stub() {
                             @Override
                             public void onAnimationFinished() throws RemoteException {
-                                onRemoteAnimationFinishedOrCancelled(false /* cancel */, evictWct);
+                                onRemoteAnimationFinished(apps);
                                 finishedCallback.onAnimationFinished();
                             }
                         };
                 Transitions.setRunningRemoteTransitionDelegate(adapter.getCallingApplication());
                 try {
-                    adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
-                            augmentedNonApps, 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);
+                    adapter.getRunner().onAnimationStart(
+                            transit, apps, wallpapers, nonApps, wrapCallback);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error starting remote animation", e);
                 }
             }
         };
-        RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
-                wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
 
-        if (mainOptions == null) {
-            mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
-        } else {
-            ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
-            mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
-            mainOptions = mainActivityOptions.toBundle();
-        }
-
-        sideOptions = sideOptions != null ? sideOptions : new Bundle();
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
         setSideStagePosition(sidePosition, wct);
-
-        mSplitLayout.setDivideRatio(splitRatio);
         if (!mMainStage.isActive()) {
-            // Build a request WCT that will launch both apps such that task 0 is on the main stage
-            // while task 1 is on the side stage.
             mMainStage.activate(wct, false /* reparent */);
         }
+
+        if (mainOptions == null) mainOptions = new Bundle();
+        addActivityOptions(mainOptions, mMainStage);
+        wct.startTask(mainTaskId, mainOptions);
+        wct.merge(sideWct, true);
+
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
+        wct.setForceTranslucent(mRootTaskInfo.token, false);
 
-        // Make sure the launch options will put tasks in the corresponding split roots
-        addActivityOptions(mainOptions, mMainStage);
-        addActivityOptions(sideOptions, mSideStage);
-
-        // Add task launch requests
-        wct.startTask(mainTaskId, mainOptions);
-        if (withIntent) {
-            wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
-        } else {
-            wct.startTask(sideTaskId, sideOptions);
-        }
-        // Using legacy transitions, so we can't use blast sync since it conflicts.
-        mTaskOrganizer.applyTransaction(wct);
-        mSyncQueue.runInSync(t -> {
-            setDividerVisibility(true, t);
-            updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
-        });
+        mSyncQueue.queue(transition, WindowManager.TRANSIT_OPEN, wct);
     }
 
-    private void onRemoteAnimationFinishedOrCancelled(boolean cancel,
-            WindowContainerTransaction evictWct) {
+    private void onRemoteAnimationFinished(RemoteAnimationTarget[] apps) {
         mIsDividerRemoteAnimating = false;
         mShouldUpdateRecents = true;
-        // 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);
+        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;
         }
+
+        final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+        prepareEvictNonOpeningChildTasks(SPLIT_POSITION_TOP_OR_LEFT, apps, evictWct);
+        prepareEvictNonOpeningChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, apps, evictWct);
+        mSyncQueue.queue(evictWct);
     }
 
     /**
@@ -882,6 +882,8 @@
             WindowContainerTransaction wct, @ExitReason int exitReason) {
         if (!mMainStage.isActive() || mIsExiting) return;
 
+        onSplitScreenExit();
+
         mRecentTasks.ifPresent(recentTasks -> {
             // Notify recents if we are exiting in a way that breaks the pair, and disable further
             // updates to splits in the recents until we enter split again
@@ -893,10 +895,13 @@
         mShouldUpdateRecents = false;
         mIsDividerRemoteAnimating = false;
 
+        mSplitLayout.getInvisibleBounds(mTempRect1);
         if (childrenToTop == null) {
             mSideStage.removeAllTasks(wct, false /* toTop */);
             mMainStage.deactivate(wct, false /* toTop */);
             wct.reorder(mRootTaskInfo.token, false /* onTop */);
+            wct.setForceTranslucent(mRootTaskInfo.token, true);
+            wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
             onTransitionAnimationComplete();
         } else {
             // Expand to top side split as full screen for fading out decor animation and dismiss
@@ -907,27 +912,32 @@
                     ? mSideStage : mMainStage;
             tempFullStage.resetBounds(wct);
             wct.setSmallestScreenWidthDp(tempFullStage.mRootTaskInfo.token,
-                    mRootTaskInfo.configuration.smallestScreenWidthDp);
+                    SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
             dismissStage.dismiss(wct, false /* toTop */);
         }
         mSyncQueue.queue(wct);
         mSyncQueue.runInSync(t -> {
             t.setWindowCrop(mMainStage.mRootLeash, null)
                     .setWindowCrop(mSideStage.mRootLeash, null);
-            t.setPosition(mMainStage.mRootLeash, 0, 0)
-                    .setPosition(mSideStage.mRootLeash, 0, 0);
             t.hide(mMainStage.mDimLayer).hide(mSideStage.mDimLayer);
             setDividerVisibility(false, t);
 
-            // In this case, exit still under progress, fade out the split decor after first WCT
-            // done and do remaining WCT after animation finished.
-            if (childrenToTop != null) {
+            if (childrenToTop == null) {
+                t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right);
+            } else {
+                // In this case, exit still under progress, fade out the split decor after first WCT
+                // done and do remaining WCT after animation finished.
                 childrenToTop.fadeOutDecor(() -> {
                     WindowContainerTransaction finishedWCT = new WindowContainerTransaction();
                     mIsExiting = false;
                     childrenToTop.dismiss(finishedWCT, true /* toTop */);
                     finishedWCT.reorder(mRootTaskInfo.token, false /* toTop */);
-                    mTaskOrganizer.applyTransaction(finishedWCT);
+                    finishedWCT.setForceTranslucent(mRootTaskInfo.token, true);
+                    finishedWCT.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+                    mSyncQueue.queue(finishedWCT);
+                    mSyncQueue.runInSync(at -> {
+                        at.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.right);
+                    });
                     onTransitionAnimationComplete();
                 });
             }
@@ -943,6 +953,47 @@
     }
 
     /**
+     * Overridden by child classes.
+     */
+    protected void onSplitScreenEnter() {
+    }
+
+    /**
+     * Overridden by child classes.
+     */
+    protected void onSplitScreenExit() {
+    }
+
+    /**
+     * Exits the split screen by finishing one of the tasks.
+     */
+    protected void exitStage(@SplitPosition int stageToClose) {
+        if (ENABLE_SHELL_TRANSITIONS) {
+            StageTaskListener stageToTop = mSideStagePosition == stageToClose
+                    ? mMainStage
+                    : mSideStage;
+            exitSplitScreen(stageToTop, EXIT_REASON_APP_FINISHED);
+        } else {
+            boolean toEnd = stageToClose == SPLIT_POSITION_BOTTOM_OR_RIGHT;
+            mSplitLayout.flingDividerToDismiss(toEnd, EXIT_REASON_APP_FINISHED);
+        }
+    }
+
+    /**
+     * Grants focus to the main or the side stages.
+     */
+    protected void grantFocusToStage(@SplitPosition int stageToFocus) {
+        IActivityTaskManager activityTaskManagerService = IActivityTaskManager.Stub.asInterface(
+                ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE));
+        try {
+            activityTaskManagerService.setFocusedTask(getTaskId(stageToFocus));
+        } catch (RemoteException | NullPointerException e) {
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                    "%s: Unable to update focus on the chosen stage, %s", TAG, e);
+        }
+    }
+
+    /**
      * Returns whether the split pair in the recent tasks list should be broken.
      */
     private boolean shouldBreakPairedTaskInRecents(@ExitReason int exitReason) {
@@ -989,6 +1040,7 @@
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
         if (mMainStage.isActive()) return;
 
+        onSplitScreenEnter();
         if (taskInfo != null) {
             setSideStagePosition(startPosition, wct);
             mSideStage.addTask(taskInfo, wct);
@@ -996,6 +1048,7 @@
         mMainStage.activate(wct, true /* includingTopTask */);
         updateWindowBounds(mSplitLayout, wct);
         wct.reorder(mRootTaskInfo.token, true);
+        wct.setForceTranslucent(mRootTaskInfo.token, false);
     }
 
     void finishEnterSplitScreen(SurfaceControl.Transaction t) {
@@ -1221,7 +1274,13 @@
         // Make the stages adjacent to each other so they occlude what's behind them.
         wct.setAdjacentRoots(mMainStage.mRootTaskInfo.token, mSideStage.mRootTaskInfo.token);
         wct.setLaunchAdjacentFlagRoot(mSideStage.mRootTaskInfo.token);
-        mTaskOrganizer.applyTransaction(wct);
+        wct.setForceTranslucent(mRootTaskInfo.token, true);
+        mSplitLayout.getInvisibleBounds(mTempRect1);
+        wct.setBounds(mSideStage.mRootTaskInfo.token, mTempRect1);
+        mSyncQueue.queue(wct);
+        mSyncQueue.runInSync(t -> {
+            t.setPosition(mSideStage.mRootLeash, mTempRect1.left, mTempRect1.top);
+        });
     }
 
     private void onRootTaskVanished() {
@@ -1375,12 +1434,18 @@
             }
         } else if (isSideStage && hasChildren && !mMainStage.isActive()) {
             // TODO (b/238697912) : Add the validation to prevent entering non-recovered status
+            onSplitScreenEnter();
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             mSplitLayout.init();
-            prepareEnterSplitScreen(wct);
+            mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
+            mMainStage.activate(wct, true /* includingTopTask */);
+            updateWindowBounds(mSplitLayout, wct);
+            wct.reorder(mRootTaskInfo.token, true);
+            wct.setForceTranslucent(mRootTaskInfo.token, false);
             mSyncQueue.queue(wct);
-            mSyncQueue.runInSync(t ->
-                    updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+            mSyncQueue.runInSync(t -> {
+                mSplitLayout.flingDividerToCenter();
+            });
         }
         if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
             mShouldUpdateRecents = true;
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
 [email protected]
[email protected]
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
new file mode 100644
index 0000000..1d8a8d5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuController.java
@@ -0,0 +1,218 @@
+/*
+ * 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.splitscreen.tv;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.SHELL_ROOT_LAYER_DIVIDER;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.view.LayoutInflater;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.split.SplitScreenConstants;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+/**
+ * Handles the interaction logic with the {@link TvSplitMenuView}.
+ * A bridge between {@link TvStageCoordinator} and {@link TvSplitMenuView}.
+ */
+public class TvSplitMenuController implements TvSplitMenuView.Listener {
+
+    private static final String TAG = TvSplitMenuController.class.getSimpleName();
+    private static final String ACTION_SHOW_MENU = "com.android.wm.shell.splitscreen.SHOW_MENU";
+    private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
+
+    private final Context mContext;
+    private final StageController mStageController;
+    private final SystemWindows mSystemWindows;
+    private final Handler mMainHandler;
+
+    private final TvSplitMenuView mSplitMenuView;
+
+    private final ActionBroadcastReceiver mActionBroadcastReceiver;
+
+    private final int mTvButtonFadeAnimationDuration;
+
+    public TvSplitMenuController(Context context, StageController stageController,
+            SystemWindows systemWindows, Handler mainHandler) {
+        mContext = context;
+        mMainHandler = mainHandler;
+        mStageController = stageController;
+        mSystemWindows = systemWindows;
+
+        mTvButtonFadeAnimationDuration = context.getResources()
+                .getInteger(R.integer.tv_window_menu_fade_animation_duration);
+
+        mSplitMenuView = (TvSplitMenuView) LayoutInflater.from(context)
+                .inflate(R.layout.tv_split_menu_view, null);
+        mSplitMenuView.setListener(this);
+
+        mActionBroadcastReceiver = new ActionBroadcastReceiver();
+    }
+
+    /**
+     * Adds the menu view for the splitscreen to SystemWindows.
+     */
+    void addSplitMenuViewToSystemWindows() {
+        final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                mContext.getResources().getDisplayMetrics().widthPixels,
+                mContext.getResources().getDisplayMetrics().heightPixels,
+                TYPE_DOCK_DIVIDER,
+                FLAG_NOT_TOUCHABLE,
+                PixelFormat.TRANSLUCENT);
+        lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
+        mSplitMenuView.setAlpha(0);
+        mSystemWindows.addView(mSplitMenuView, lp, DEFAULT_DISPLAY, SHELL_ROOT_LAYER_DIVIDER);
+    }
+
+    /**
+     * Removes the menu view for the splitscreen from SystemWindows.
+     */
+    void removeSplitMenuViewFromSystemWindows() {
+        mSystemWindows.removeView(mSplitMenuView);
+    }
+
+    /**
+     * Registers BroadcastReceiver when split screen mode is entered.
+     */
+    void registerBroadcastReceiver() {
+        mActionBroadcastReceiver.register();
+    }
+
+    /**
+     * Unregisters BroadcastReceiver when split screen mode is entered.
+     */
+    void unregisterBroadcastReceiver() {
+        mActionBroadcastReceiver.unregister();
+    }
+
+    @Override
+    public void onBackPress() {
+        setMenuVisibility(false);
+    }
+
+    @Override
+    public void onFocusStage(@SplitScreenConstants.SplitPosition int stageToFocus) {
+        setMenuVisibility(false);
+        mStageController.grantFocusToStage(stageToFocus);
+    }
+
+    @Override
+    public void onCloseStage(@SplitScreenConstants.SplitPosition int stageToClose) {
+        setMenuVisibility(false);
+        mStageController.exitStage(stageToClose);
+    }
+
+    @Override
+    public void onSwapPress() {
+        mStageController.swapStages();
+    }
+
+    private void setMenuVisibility(boolean visible) {
+        applyMenuVisibility(visible);
+        setMenuFocus(visible);
+    }
+
+    private void applyMenuVisibility(boolean visible) {
+        float alphaTarget = visible ? 1F : 0F;
+
+        if (mSplitMenuView.getAlpha() == alphaTarget) {
+            return;
+        }
+
+        mSplitMenuView.animate()
+                .alpha(alphaTarget)
+                .setDuration(mTvButtonFadeAnimationDuration)
+                .withStartAction(() -> {
+                    if (alphaTarget != 0) {
+                        mSplitMenuView.setVisibility(VISIBLE);
+                    }
+                })
+                .withEndAction(() -> {
+                    if (alphaTarget == 0) {
+                        mSplitMenuView.setVisibility(INVISIBLE);
+                    }
+                });
+
+    }
+
+    private void setMenuFocus(boolean focused) {
+        try {
+            WindowManagerGlobal.getWindowSession().grantEmbeddedWindowFocus(null,
+                    mSystemWindows.getFocusGrantToken(mSplitMenuView), focused);
+        } catch (RemoteException e) {
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                    "%s: Unable to update focus, %s", TAG, e);
+        }
+    }
+
+    interface StageController {
+        void grantFocusToStage(@SplitScreenConstants.SplitPosition  int stageToFocus);
+        void exitStage(@SplitScreenConstants.SplitPosition  int stageToClose);
+        void swapStages();
+    }
+
+    private class ActionBroadcastReceiver extends BroadcastReceiver {
+
+        final IntentFilter mIntentFilter;
+        {
+            mIntentFilter = new IntentFilter();
+            mIntentFilter.addAction(ACTION_SHOW_MENU);
+        }
+        boolean mRegistered = false;
+
+        void register() {
+            if (mRegistered) return;
+
+            mContext.registerReceiverForAllUsers(this, mIntentFilter, SYSTEMUI_PERMISSION,
+                    mMainHandler);
+            mRegistered = true;
+        }
+
+        void unregister() {
+            if (!mRegistered) return;
+
+            mContext.unregisterReceiver(this);
+            mRegistered = false;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+
+            if (ACTION_SHOW_MENU.equals(action)) {
+                setMenuVisibility(true);
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java
new file mode 100644
index 0000000..88e9757
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitMenuView.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen.tv;
+
+import static android.view.KeyEvent.ACTION_DOWN;
+import static android.view.KeyEvent.KEYCODE_BACK;
+
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.annotation.Nullable;
+
+import com.android.wm.shell.R;
+import com.android.wm.shell.common.split.SplitScreenConstants;
+
+/**
+ * A View for the Menu Window.
+ */
+public class TvSplitMenuView extends LinearLayout implements View.OnClickListener {
+
+    private Listener mListener;
+
+    public TvSplitMenuView(Context context) {
+        super(context);
+    }
+
+    public TvSplitMenuView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public TvSplitMenuView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        initButtons();
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (mListener == null) return;
+
+        final int id = v.getId();
+        if (id == R.id.tv_split_main_menu_focus_button) {
+            mListener.onFocusStage(SPLIT_POSITION_TOP_OR_LEFT);
+        } else if (id == R.id.tv_split_main_menu_close_button) {
+            mListener.onCloseStage(SPLIT_POSITION_TOP_OR_LEFT);
+        } else if (id == R.id.tv_split_side_menu_focus_button) {
+            mListener.onFocusStage(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        } else if (id == R.id.tv_split_side_menu_close_button) {
+            mListener.onCloseStage(SPLIT_POSITION_BOTTOM_OR_RIGHT);
+        } else if (id == R.id.tv_split_menu_swap_stages) {
+            mListener.onSwapPress();
+        }
+    }
+
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getAction() == ACTION_DOWN) {
+            if (event.getKeyCode() == KEYCODE_BACK) {
+                if (mListener != null) {
+                    mListener.onBackPress();
+                    return true;
+                }
+            }
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    private void initButtons() {
+        findViewById(R.id.tv_split_main_menu_focus_button).setOnClickListener(this);
+        findViewById(R.id.tv_split_main_menu_close_button).setOnClickListener(this);
+        findViewById(R.id.tv_split_side_menu_focus_button).setOnClickListener(this);
+        findViewById(R.id.tv_split_side_menu_close_button).setOnClickListener(this);
+        findViewById(R.id.tv_split_menu_swap_stages).setOnClickListener(this);
+    }
+
+    void setListener(Listener listener) {
+        mListener = listener;
+    }
+
+    interface Listener {
+        /** "Back" button from the remote control */
+        void onBackPress();
+
+        /** Menu Action Buttons */
+
+        void onFocusStage(@SplitScreenConstants.SplitPosition int stageToFocus);
+
+        void onCloseStage(@SplitScreenConstants.SplitPosition int stageToClose);
+
+        void onSwapPress();
+    }
+}
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
new file mode 100644
index 0000000..46d2a5a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvSplitScreenController.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.splitscreen.tv;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TransactionPool;
+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.StageCoordinator;
+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.Transitions;
+
+import java.util.Optional;
+
+/**
+ * Class inherits from {@link SplitScreenController} and provides {@link TvStageCoordinator}
+ * for Split Screen on TV.
+ */
+public class TvSplitScreenController extends SplitScreenController {
+    private final ShellTaskOrganizer mTaskOrganizer;
+    private final SyncTransactionQueue mSyncQueue;
+    private final Context mContext;
+    private final ShellExecutor mMainExecutor;
+    private final DisplayController mDisplayController;
+    private final DisplayImeController mDisplayImeController;
+    private final DisplayInsetsController mDisplayInsetsController;
+    private final Transitions mTransitions;
+    private final TransactionPool mTransactionPool;
+    private final IconProvider mIconProvider;
+    private final Optional<RecentTasksController> mRecentTasksOptional;
+
+    private final Handler mMainHandler;
+    private final SystemWindows mSystemWindows;
+
+    public TvSplitScreenController(Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            ShellController shellController,
+            ShellTaskOrganizer shellTaskOrganizer,
+            SyncTransactionQueue syncQueue,
+            RootTaskDisplayAreaOrganizer rootTDAOrganizer,
+            DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController,
+            DragAndDropController dragAndDropController,
+            Transitions transitions,
+            TransactionPool transactionPool,
+            IconProvider iconProvider,
+            Optional<RecentTasksController> recentTasks,
+            ShellExecutor mainExecutor,
+            Handler mainHandler,
+            SystemWindows systemWindows) {
+        super(context, shellInit, shellCommandHandler, shellController, shellTaskOrganizer,
+                syncQueue, rootTDAOrganizer, displayController, displayImeController,
+                displayInsetsController, dragAndDropController, transitions, transactionPool,
+                iconProvider, recentTasks, mainExecutor);
+
+        mTaskOrganizer = shellTaskOrganizer;
+        mSyncQueue = syncQueue;
+        mContext = context;
+        mMainExecutor = mainExecutor;
+        mDisplayController = displayController;
+        mDisplayImeController = displayImeController;
+        mDisplayInsetsController = displayInsetsController;
+        mTransitions = transitions;
+        mTransactionPool = transactionPool;
+        mIconProvider = iconProvider;
+        mRecentTasksOptional = recentTasks;
+
+        mMainHandler = mainHandler;
+        mSystemWindows = systemWindows;
+    }
+
+    /**
+     * Provides Tv-specific StageCoordinator.
+     * @return {@link TvStageCoordinator}
+     */
+    @Override
+    protected StageCoordinator createStageCoordinator() {
+        return new TvStageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
+                mTaskOrganizer, mDisplayController, mDisplayImeController,
+                mDisplayInsetsController, mTransitions, mTransactionPool,
+                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
new file mode 100644
index 0000000..4d563fb
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/tv/TvStageCoordinator.java
@@ -0,0 +1,94 @@
+/*
+ * 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.splitscreen.tv;
+
+import android.content.Context;
+import android.os.Handler;
+
+import com.android.launcher3.icons.IconProvider;
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.common.SystemWindows;
+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.StageCoordinator;
+import com.android.wm.shell.transition.Transitions;
+
+import java.util.Optional;
+
+/**
+ * Expands {@link StageCoordinator} functionality with Tv-specific methods.
+ */
+public class TvStageCoordinator extends StageCoordinator
+        implements TvSplitMenuController.StageController {
+
+    private final TvSplitMenuController mTvSplitMenuController;
+
+    public TvStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
+            ShellTaskOrganizer taskOrganizer, DisplayController displayController,
+            DisplayImeController displayImeController,
+            DisplayInsetsController displayInsetsController, Transitions transitions,
+            TransactionPool transactionPool,
+            IconProvider iconProvider, ShellExecutor mainExecutor,
+            Handler mainHandler,
+            Optional<RecentTasksController> recentTasks,
+            SystemWindows systemWindows) {
+        super(context, displayId, syncQueue, taskOrganizer, displayController, displayImeController,
+                displayInsetsController, transitions, transactionPool, iconProvider,
+                mainExecutor, recentTasks);
+
+        mTvSplitMenuController = new TvSplitMenuController(context, this,
+                systemWindows, mainHandler);
+
+    }
+
+    @Override
+    protected void onSplitScreenEnter() {
+        mTvSplitMenuController.addSplitMenuViewToSystemWindows();
+        mTvSplitMenuController.registerBroadcastReceiver();
+    }
+
+    @Override
+    protected void onSplitScreenExit() {
+        mTvSplitMenuController.unregisterBroadcastReceiver();
+        mTvSplitMenuController.removeSplitMenuViewFromSystemWindows();
+    }
+
+    @Override
+    public void grantFocusToStage(@SplitScreenConstants.SplitPosition int stageToFocus) {
+        super.grantFocusToStage(stageToFocus);
+    }
+
+    @Override
+    public void exitStage(@SplitScreenConstants.SplitPosition int stageToClose) {
+        super.exitStage(stageToClose);
+    }
+
+    /**
+     * Swaps the stages inside the SplitLayout.
+     */
+    @Override
+    public void swapStages() {
+        onDoubleTappedDivider();
+    }
+
+}
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..bcf4fbd 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
@@ -35,10 +35,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,8 +51,8 @@
 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;
@@ -77,13 +81,22 @@
             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);
+            }, this);
+        }
     }
 
     @Nullable
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..4c927b6 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
@@ -554,6 +554,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();
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 6388ca1..b647f43 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
@@ -139,39 +139,48 @@
                 .build();
 
         try {
-            SurfaceControl.LayerCaptureArgs args =
-                    new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
-                            .setCaptureSecureLayers(true)
-                            .setAllowProtected(true)
-                            .setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
-                            .build();
-            SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
-                    SurfaceControl.captureLayers(args);
-            if (screenshotBuffer == null) {
-                Slog.w(TAG, "Unable to take screenshot of display");
-                return;
-            }
+            if (change.getSnapshot() != null) {
+                mScreenshotLayer = change.getSnapshot();
+                t.reparent(mScreenshotLayer, mAnimLeash);
+                mStartLuma = change.getSnapshotLuma();
+            } else {
+                SurfaceControl.LayerCaptureArgs args =
+                        new SurfaceControl.LayerCaptureArgs.Builder(mSurfaceControl)
+                                .setCaptureSecureLayers(true)
+                                .setAllowProtected(true)
+                                .setSourceCrop(new Rect(0, 0, mStartWidth, mStartHeight))
+                                .build();
+                SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+                        SurfaceControl.captureLayers(args);
+                if (screenshotBuffer == null) {
+                    Slog.w(TAG, "Unable to take screenshot of display");
+                    return;
+                }
 
-            mScreenshotLayer = new SurfaceControl.Builder(session)
-                    .setParent(mAnimLeash)
-                    .setBLASTLayer()
-                    .setSecure(screenshotBuffer.containsSecureLayers())
-                    .setOpaque(true)
-                    .setCallsite("ShellRotationAnimation")
-                    .setName("RotationLayer")
-                    .build();
+                mScreenshotLayer = new SurfaceControl.Builder(session)
+                        .setParent(mAnimLeash)
+                        .setBLASTLayer()
+                        .setSecure(screenshotBuffer.containsSecureLayers())
+                        .setOpaque(true)
+                        .setCallsite("ShellRotationAnimation")
+                        .setName("RotationLayer")
+                        .build();
+
+                final ColorSpace colorSpace = screenshotBuffer.getColorSpace();
+                final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
+                t.setDataSpace(mScreenshotLayer, colorSpace.getDataSpace());
+                t.setBuffer(mScreenshotLayer, hardwareBuffer);
+                t.show(mScreenshotLayer);
+                if (!isCustomRotate()) {
+                    mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
+                }
+            }
 
             t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
             t.show(mAnimLeash);
             // Crop the real content in case it contains a larger child layer, e.g. wallpaper.
             t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
 
-            final ColorSpace colorSpace = screenshotBuffer.getColorSpace();
-            final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
-            t.setDataSpace(mScreenshotLayer, colorSpace.getDataSpace());
-            t.setBuffer(mScreenshotLayer, hardwareBuffer);
-            t.show(mScreenshotLayer);
-
             if (!isCustomRotate()) {
                 mBackColorSurface = new SurfaceControl.Builder(session)
                         .setParent(rootLeash)
@@ -181,8 +190,6 @@
                         .setName("BackColorSurface")
                         .build();
 
-                mStartLuma = getMedianBorderLuma(hardwareBuffer, colorSpace);
-
                 t.setLayer(mBackColorSurface, -1);
                 t.setColor(mBackColorSurface, new float[]{mStartLuma, mStartLuma, mStartLuma});
                 t.show(mBackColorSurface);
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/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index ad53956..83aa539 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -148,7 +148,13 @@
         public void onClick(View v) {
             final int id = v.getId();
             if (id == R.id.close_window) {
-                mActivityTaskManager.removeTask(mTaskId);
+                WindowContainerTransaction wct = new WindowContainerTransaction();
+                wct.removeTask(mTaskToken);
+                if (Transitions.ENABLE_SHELL_TRANSITIONS) {
+                    mTransitionStarter.startRemoveTransition(wct);
+                } else {
+                    mSyncQueue.queue(wct);
+                }
             } else if (id == R.id.maximize_window) {
                 WindowContainerTransaction wct = new WindowContainerTransaction();
                 RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 8b13721..5040bc3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -34,7 +34,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopModeConstants;
+import com.android.wm.shell.desktopmode.DesktopMode;
 
 /**
  * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
@@ -164,7 +164,7 @@
         View caption = mResult.mRootView.findViewById(R.id.caption);
         caption.setOnTouchListener(mOnCaptionTouchListener);
         View maximize = caption.findViewById(R.id.maximize_window);
-        if (DesktopModeConstants.IS_FEATURE_ENABLED) {
+        if (DesktopMode.IS_SUPPORTED) {
             // Hide maximize button when desktop mode is available
             maximize.setVisibility(View.GONE);
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
index f512b0d..3d01495 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragResizeInputListener.java
@@ -87,7 +87,7 @@
         try {
             mWindowSession.grantInputChannel(
                     mDisplayId,
-                    new SurfaceControl(mDecorationSurface, TAG),
+                    mDecorationSurface,
                     mFakeWindow,
                     null /* hostInputToken */,
                     FLAG_NOT_FOCUSABLE,
@@ -150,8 +150,7 @@
             mWindowSession.updateInputChannel(
                     mInputChannel.getToken(),
                     mDisplayId,
-                    new SurfaceControl(
-                            mDecorationSurface, "DragResizeInputListener#setTouchRegion"),
+                    mDecorationSurface,
                     FLAG_NOT_FOCUSABLE,
                     PRIVATE_FLAG_TRUSTED_OVERLAY,
                     touchRegion);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 5e64a06..3e3a864 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -66,6 +66,7 @@
     final DisplayController mDisplayController;
     final ShellTaskOrganizer mTaskOrganizer;
     final Supplier<SurfaceControl.Builder> mSurfaceControlBuilderSupplier;
+    final Supplier<SurfaceControl.Transaction> mSurfaceControlTransactionSupplier;
     final Supplier<WindowContainerTransaction> mWindowContainerTransactionSupplier;
     final SurfaceControlViewHostFactory mSurfaceControlViewHostFactory;
     private final DisplayController.OnDisplaysChangedListener mOnDisplaysChangedListener =
@@ -89,7 +90,8 @@
     SurfaceControl mDecorationContainerSurface;
     SurfaceControl mTaskBackgroundSurface;
 
-    private final CaptionWindowManager mCaptionWindowManager;
+    SurfaceControl mCaptionContainerSurface;
+    private CaptionWindowManager mCaptionWindowManager;
     private SurfaceControlViewHost mViewHost;
 
     private final Rect mCaptionInsetsRect = new Rect();
@@ -103,8 +105,8 @@
             RunningTaskInfo taskInfo,
             SurfaceControl taskSurface) {
         this(context, displayController, taskOrganizer, taskInfo, taskSurface,
-                SurfaceControl.Builder::new, WindowContainerTransaction::new,
-                new SurfaceControlViewHostFactory() {});
+                SurfaceControl.Builder::new, SurfaceControl.Transaction::new,
+                WindowContainerTransaction::new, new SurfaceControlViewHostFactory() {});
     }
 
     WindowDecoration(
@@ -114,6 +116,7 @@
             RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
             Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+            Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
             Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
             SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
         mContext = context;
@@ -122,16 +125,12 @@
         mTaskInfo = taskInfo;
         mTaskSurface = taskSurface;
         mSurfaceControlBuilderSupplier = surfaceControlBuilderSupplier;
+        mSurfaceControlTransactionSupplier = surfaceControlTransactionSupplier;
         mWindowContainerTransactionSupplier = windowContainerTransactionSupplier;
         mSurfaceControlViewHostFactory = surfaceControlViewHostFactory;
 
         mDisplay = mDisplayController.getDisplay(mTaskInfo.displayId);
         mDecorWindowContext = mContext.createConfigurationContext(mTaskInfo.getConfiguration());
-
-        // Put caption under task surface because ViewRootImpl sets the destination frame of
-        // windowless window layers and BLASTBufferQueue#update() doesn't support offset.
-        mCaptionWindowManager =
-                new CaptionWindowManager(mTaskInfo.getConfiguration(), mTaskSurface);
     }
 
     /**
@@ -213,6 +212,7 @@
         startT.setPosition(
                         mDecorationContainerSurface, decorContainerOffsetX, decorContainerOffsetY)
                 .setWindowCrop(mDecorationContainerSurface, outResult.mWidth, outResult.mHeight)
+                // TODO(b/244455401): Change the z-order when it's better organized
                 .setLayer(mDecorationContainerSurface, mTaskInfo.numActivities + 1)
                 .show(mDecorationContainerSurface);
 
@@ -234,12 +234,35 @@
         startT.setWindowCrop(mTaskBackgroundSurface, taskBounds.width(), taskBounds.height())
                 .setShadowRadius(mTaskBackgroundSurface, shadowRadius)
                 .setColor(mTaskBackgroundSurface, mTmpColor)
+                // TODO(b/244455401): Change the z-order when it's better organized
                 .setLayer(mTaskBackgroundSurface, -1)
                 .show(mTaskBackgroundSurface);
 
+        // CaptionContainerSurface, CaptionWindowManager
+        if (mCaptionContainerSurface == null) {
+            final SurfaceControl.Builder builder = mSurfaceControlBuilderSupplier.get();
+            mCaptionContainerSurface = builder
+                    .setName("Caption container of Task=" + mTaskInfo.taskId)
+                    .setContainerLayer()
+                    .setParent(mDecorationContainerSurface)
+                    .build();
+        }
+
+        final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity);
+        startT.setPosition(
+                        mCaptionContainerSurface, -decorContainerOffsetX, -decorContainerOffsetY)
+                .setWindowCrop(mCaptionContainerSurface, taskBounds.width(), captionHeight)
+                .show(mCaptionContainerSurface);
+
+        if (mCaptionWindowManager == null) {
+            // Put caption under a container surface because ViewRootImpl sets the destination frame
+            // of windowless window layers and BLASTBufferQueue#update() doesn't support offset.
+            mCaptionWindowManager = new CaptionWindowManager(
+                    mTaskInfo.getConfiguration(), mCaptionContainerSurface);
+        }
+
         // Caption view
         mCaptionWindowManager.setConfiguration(taskConfig);
-        final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity);
         final WindowManager.LayoutParams lp =
                 new WindowManager.LayoutParams(taskBounds.width(), captionHeight,
                         WindowManager.LayoutParams.TYPE_APPLICATION,
@@ -262,7 +285,7 @@
             mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight;
             wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES);
         } else {
-            outResult.mRootView.setVisibility(View.GONE);
+            startT.hide(mCaptionContainerSurface);
         }
 
         // Task surface itself
@@ -298,14 +321,30 @@
             mViewHost = null;
         }
 
+        mCaptionWindowManager = null;
+
+        final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
+        boolean released = false;
+        if (mCaptionContainerSurface != null) {
+            t.remove(mCaptionContainerSurface);
+            mCaptionContainerSurface = null;
+            released = true;
+        }
+
         if (mDecorationContainerSurface != null) {
-            mDecorationContainerSurface.release();
+            t.remove(mDecorationContainerSurface);
             mDecorationContainerSurface = null;
+            released = true;
         }
 
         if (mTaskBackgroundSurface != null) {
-            mTaskBackgroundSurface.release();
+            t.remove(mTaskBackgroundSurface);
             mTaskBackgroundSurface = null;
+            released = true;
+        }
+
+        if (released) {
+            t.apply();
         }
 
         final WindowContainerTransaction wct = mWindowContainerTransactionSupplier.get();
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 cb74315..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,
@@ -151,15 +178,15 @@
     assertLayers {
         if (landscapePosLeft) {
             this.splitAppLayerBoundsSnapToDivider(
-                    component, landscapePosLeft, portraitPosTop, endRotation)
+                component, landscapePosLeft, portraitPosTop, endRotation)
+        } else {
+            this.splitAppLayerBoundsSnapToDivider(
+                component, landscapePosLeft, portraitPosTop, endRotation)
                 .then()
                 .isInvisible(component)
                 .then()
                 .splitAppLayerBoundsSnapToDivider(
                     component, landscapePosLeft, portraitPosTop, endRotation)
-        } else {
-            this.splitAppLayerBoundsSnapToDivider(
-                component, landscapePosLeft, portraitPosTop, endRotation)
         }
     }
 }
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 67d7aca..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)
@@ -86,8 +82,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                            repetitions = 3)
+                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
         }
 
         const val FIND_OBJECT_TIMEOUT = 2000L
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 293eb7c..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
@@ -18,7 +18,6 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
-import android.platform.test.annotations.Presubmit
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.filters.RequiresDevice
@@ -50,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
@@ -92,7 +89,7 @@
             }
         }
 
-    @Presubmit
+    @FlakyTest(bugId = 242088970)
     @Test
     fun testAppIsVisibleAtEnd() {
         testSpec.assertLayersEnd {
@@ -125,7 +122,7 @@
         super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
-    @Postsubmit
+    @FlakyTest(bugId = 242088970)
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() =
         super.taskBarLayerIsVisibleAtStartAndEnd()
@@ -135,4 +132,28 @@
     @Test
     override fun taskBarWindowIsAlwaysVisible() =
         super.taskBarWindowIsAlwaysVisible()
+
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 242088970)
+    @Test
+    override fun statusBarLayerIsVisibleAtStartAndEnd() =
+        super.statusBarLayerIsVisibleAtStartAndEnd()
+
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 242088970)
+    @Test
+    override fun statusBarLayerPositionAtStartAndEnd() =
+        super.statusBarLayerPositionAtStartAndEnd()
+
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 242088970)
+    @Test
+    override fun statusBarWindowIsAlwaysVisible() =
+        super.statusBarWindowIsAlwaysVisible()
+
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 242088970)
+    @Test
+    override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
+        super.visibleWindowsShownMoreThanOneConsecutiveEntry()
 }
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/helpers/LaunchBubbleHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt
index 6695c17..1b8a44b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/LaunchBubbleHelper.kt
@@ -27,7 +27,6 @@
 ) {
 
     companion object {
-        const val TEST_REPETITIONS = 1
         const val TIMEOUT_MS = 3_000L
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
index e7f9d9a..52e5d7e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/SplitScreenHelper.kt
@@ -42,7 +42,6 @@
 ) : BaseAppHelper(instrumentation, activityLabel, componentInfo) {
 
     companion object {
-        const val TEST_REPETITIONS = 1
         const val TIMEOUT_MS = 3_000L
         const val DRAG_DURATION_MS = 1_000L
         const val NOTIFICATION_SCROLLER = "notification_stack_scroller"
@@ -98,13 +97,29 @@
             secondaryApp: IComponentMatcher,
         ) {
             wmHelper.StateSyncBuilder()
-                .withAppTransitionIdle()
                 .withWindowSurfaceAppeared(primaryApp)
                 .withWindowSurfaceAppeared(secondaryApp)
                 .withSplitDividerVisible()
                 .waitForAndVerify()
         }
 
+        fun enterSplit(
+            wmHelper: WindowManagerStateHelper,
+            tapl: LauncherInstrumentation,
+            primaryApp: SplitScreenHelper,
+            secondaryApp: SplitScreenHelper
+        ) {
+            tapl.workspace.switchToOverview().dismissAllTasks()
+            primaryApp.launchViaIntent(wmHelper)
+            secondaryApp.launchViaIntent(wmHelper)
+            tapl.goHome()
+            wmHelper.StateSyncBuilder()
+                .withHomeActivityVisible()
+                .waitForAndVerify()
+            splitFromOverview(tapl)
+            waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+        }
+
         fun splitFromOverview(tapl: LauncherInstrumentation) {
             // Note: The initial split position in landscape is different between tablet and phone.
             // In landscape, tablet will let the first app split to right side, and phone will
@@ -268,24 +283,35 @@
                 ?.layerStackSpace
                 ?: error("Display not found")
             val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
-            dividerBar.drag(Point(displayBounds.width * 2 / 3, displayBounds.height * 2 / 3))
+            dividerBar.drag(Point(displayBounds.width * 1 / 3, displayBounds.height * 2 / 3))
 
             wmHelper.StateSyncBuilder()
-                .withAppTransitionIdle()
                 .withWindowSurfaceDisappeared(SPLIT_DECOR_MANAGER)
                 .waitForAndVerify()
         }
 
         fun dragDividerToDismissSplit(
             device: UiDevice,
-            wmHelper: WindowManagerStateHelper
+            wmHelper: WindowManagerStateHelper,
+            dragToRight: Boolean,
+            dragToBottom: Boolean
         ) {
             val displayBounds = wmHelper.currentState.layerState
                 .displays.firstOrNull { !it.isVirtual }
                 ?.layerStackSpace
                 ?: error("Display not found")
             val dividerBar = device.wait(Until.findObject(dividerBarSelector), TIMEOUT_MS)
-            dividerBar.drag(Point(displayBounds.width * 4 / 5, displayBounds.height * 4 / 5))
+            dividerBar.drag(Point(
+                if (dragToRight) {
+                    displayBounds.width * 4 / 5
+                } else {
+                    displayBounds.width * 1 / 5
+                },
+                if (dragToBottom) {
+                    displayBounds.height * 4 / 5
+                } else {
+                    displayBounds.height * 1 / 5
+                }))
         }
 
         fun doubleTapDividerToSwitch(device: UiDevice) {
@@ -297,7 +323,7 @@
             dividerBar.click()
         }
 
-        fun copyContentFromLeftToRight(
+        fun copyContentInSplit(
             instrumentation: Instrumentation,
             device: UiDevice,
             sourceApp: IComponentNameMatcher,
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 d194472..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)
@@ -130,7 +132,7 @@
         testSpec.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
-                current.visibleRegion.coversAtMost(previous.visibleRegion.region)
+                current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
             }
         }
     }
@@ -185,8 +187,7 @@
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    repetitions = 3
+                    supportedRotations = listOf(Surface.ROTATION_0)
                 )
         }
     }
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 507562b..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
@@ -46,7 +49,7 @@
 /**
  * Test entering pip while changing orientation (from app in landscape to pip window in portrait)
  *
- * To run this test: `atest EnterPipToOtherOrientationTest:EnterPipToOtherOrientationTest`
+ * To run this test: `atest WMShellFlickerTests:EnterPipToOtherOrientationTest`
  *
  * Actions:
  *     Launch [testApp] on a fixed portrait orientation
@@ -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.
@@ -246,8 +243,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    repetitions = 3
+                    supportedRotations = listOf(Surface.ROTATION_0)
                 )
         }
     }
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..0f7d8a95 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 b5a3c78..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
@@ -100,7 +98,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
+                    supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
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 1d26614..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.
@@ -125,7 +123,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3)
+                supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
index b71a9d8..3bffef0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -86,8 +86,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                            repetitions = 3)
+                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 31a39c1..75d25e6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -105,8 +105,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                            repetitions = 3)
+                    .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
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 fd661cf..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 {
@@ -178,8 +178,7 @@
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    repetitions = 3
+                    supportedRotations = listOf(Surface.ROTATION_0)
                 )
         }
     }
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 b3f0fb9..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()
@@ -89,7 +85,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3
+                supportedRotations = listOf(Surface.ROTATION_0)
             )
         }
     }
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 8bd5c54..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.
@@ -105,7 +93,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0), repetitions = 3
+                supportedRotations = listOf(Surface.ROTATION_0)
             )
         }
     }
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 454927e..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
      */
@@ -116,8 +105,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                    repetitions = 3)
+                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
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 09248a1..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.
@@ -264,8 +205,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
-                repetitions = 3
+                supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
             )
         }
     }
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 6d64cb9..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,32 +181,14 @@
     /** {@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
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
-                    repetitions = 1)
+                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
         }
     }
 }
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 d238814..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
@@ -30,8 +31,6 @@
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import com.android.wm.shell.flicker.layerKeepVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsKeepVisible
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,60 +48,53 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Group1
 class CopyContentInSplit(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
-    protected val textEditApp = SplitScreenHelper.getIme(instrumentation)
-
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
+    private val textEditApp = SplitScreenHelper.getIme(instrumentation)
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    textEditApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(primaryApp.appName)
-                        .dragToSplitscreen(primaryApp.`package`, textEditApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, textEditApp, primaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, textEditApp)
             }
             transitions {
-                SplitScreenHelper.copyContentFromLeftToRight(
+                SplitScreenHelper.copyContentInSplit(
                     instrumentation, device, primaryApp, textEditApp)
             }
         }
 
+    @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 = true, portraitPosTop = true)
+        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun textEditAppBoundsKeepVisible() = testSpec.splitAppLayerBoundsKeepVisible(
-        textEditApp, landscapePosLeft = false, portraitPosTop = false)
+        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)
@@ -178,7 +170,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 ba40c27..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
@@ -26,6 +27,7 @@
 import com.android.server.wm.flicker.annotation.Group1
 import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesInvisible
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
@@ -33,8 +35,6 @@
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
 import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -53,62 +53,63 @@
 @Group1
 class DismissSplitScreenByDivider (testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    tapl.goHome()
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
-                SplitScreenHelper.dragDividerToDismissSplit(device, wmHelper)
+                if (tapl.isTablet) {
+                    SplitScreenHelper.dragDividerToDismissSplit(device, wmHelper,
+                        dragToRight = false, dragToBottom = true)
+                } else {
+                    SplitScreenHelper.dragDividerToDismissSplit(device, wmHelper,
+                        dragToRight = true, dragToBottom = true)
+                }
                 wmHelper.StateSyncBuilder()
-                    .withAppTransitionIdle()
                     .withFullScreenApp(secondaryApp)
                     .waitForAndVerify()
             }
         }
 
+    @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 = false, portraitPosTop = false)
+        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsFullscreenAtEnd() {
         testSpec.assertLayers {
             this.isVisible(secondaryApp)
+                .isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
                 .then()
                 .isInvisible(secondaryApp)
+                .isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
                 .then()
-                .isVisible(secondaryApp)
+                .isVisible(secondaryApp, isOptional = true)
+                .isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT, isOptional = true)
+                .then()
+                .contains(SPLIT_SCREEN_DIVIDER_COMPONENT)
+                .then()
                 .invoke("secondaryAppBoundsIsFullscreenAtEnd") {
                     val displayBounds = WindowUtils.getDisplayBounds(testSpec.endRotation)
                     it.visibleRegion(secondaryApp).coversExactly(displayBounds)
@@ -116,10 +117,12 @@
         }
     }
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun primaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(primaryApp)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(secondaryApp)
@@ -195,7 +198,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 6828589..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
@@ -30,8 +31,6 @@
 import com.android.wm.shell.flicker.layerBecomesInvisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
 import com.android.wm.shell.flicker.splitScreenDividerBecomesInvisible
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -52,61 +51,53 @@
     testSpec: FlickerTestParameter
 ) : SplitScreenBase(testSpec) {
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
                 tapl.goHome()
                 wmHelper.StateSyncBuilder()
-                    .withAppTransitionIdle()
                     .withHomeActivityVisible()
                     .waitForAndVerify()
             }
         }
 
+    @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 = false, portraitPosTop = false)
+        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+        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)
@@ -182,7 +173,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 9ac7c23..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
@@ -31,8 +32,6 @@
 import com.android.wm.shell.flicker.helpers.SplitScreenHelper
 import com.android.wm.shell.flicker.layerKeepVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsChanges
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,40 +50,28 @@
 @Group1
 class DragDividerToResize (testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    tapl.goHome()
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, 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() {
@@ -97,23 +84,27 @@
         }
     }
 
+    @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 = false, portraitPosTop = false)
+        primaryApp, landscapePosLeft = true, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsChanges() = testSpec.splitAppLayerBoundsChanges(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+        secondaryApp, landscapePosLeft = false, portraitPosTop = true)
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -186,11 +177,10 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 supportedRotations = listOf(Surface.ROTATION_0),
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
-                listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
+                    listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
         }
     }
 }
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 8401c1a..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)
@@ -180,7 +221,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 168afda..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)
@@ -195,7 +233,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
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 c1fce5f..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)
@@ -183,7 +224,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
             )
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 8cb5d7c..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)
@@ -170,8 +176,7 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS)
+            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
         }
     }
 }
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 1530561..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
@@ -31,8 +32,6 @@
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
 import com.android.wm.shell.flicker.layerKeepVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,25 +50,11 @@
 @Group1
 class SwitchAppByDoubleTapDivider (testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
-                }
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
             }
             transitions {
                 SplitScreenHelper.doubleTapDividerToSwitch(device)
@@ -79,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 = true, portraitPosTop = true)
+        primaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        secondaryApp, landscapePosLeft = false, portraitPosTop = false)
+        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)
@@ -180,7 +172,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 20544bd..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
@@ -30,8 +31,6 @@
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,31 +50,16 @@
 class SwitchBackToSplitFromAnotherApp(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
     val thirdApp = SplitScreenHelper.getNonResizeable(instrumentation)
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
 
-                    thirdApp.launchViaIntent(wmHelper)
-                    wmHelper.StateSyncBuilder()
-                        .withAppTransitionIdle()
-                        .withWindowSurfaceAppeared(thirdApp)
-                        .waitForAndVerify()
-                }
+                thirdApp.launchViaIntent(wmHelper)
+                wmHelper.StateSyncBuilder()
+                    .withWindowSurfaceAppeared(thirdApp)
+                    .waitForAndVerify()
             }
             transitions {
                 tapl.launchedAppState.quickSwitchToPreviousApp()
@@ -83,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 = false, portraitPosTop = false)
+        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+        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)
@@ -184,7 +175,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 5a8604f..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
@@ -30,8 +31,6 @@
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -50,31 +49,16 @@
 @Group1
 class SwitchBackToSplitFromHome(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
 
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withAppTransitionIdle()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                }
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
             }
             transitions {
                 tapl.workspace.quickSwitchToPreviousApp()
@@ -82,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 = false, portraitPosTop = false)
+        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+        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)
@@ -183,7 +174,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
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 adea66a..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
@@ -30,8 +31,6 @@
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitScreenDividerBecomesVisible
-import org.junit.Assume
-import org.junit.Before
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -50,31 +49,16 @@
 @Group1
 class SwitchBackToSplitFromRecent(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
 
-    // TODO(b/231399940): Remove this once we can use recent shortcut to enter split.
-    @Before
-    open fun before() {
-        Assume.assumeTrue(tapl.isTablet)
-    }
-
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    primaryApp.launchViaIntent(wmHelper)
-                    // TODO(b/231399940): Use recent shortcut to enter split.
-                    tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
-                    SplitScreenHelper.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
+                SplitScreenHelper.enterSplit(wmHelper, tapl, primaryApp, secondaryApp)
 
-                    tapl.goHome()
-                    wmHelper.StateSyncBuilder()
-                        .withAppTransitionIdle()
-                        .withHomeActivityVisible()
-                        .waitForAndVerify()
-                }
+                tapl.goHome()
+                wmHelper.StateSyncBuilder()
+                    .withHomeActivityVisible()
+                    .waitForAndVerify()
             }
             transitions {
                 tapl.workspace.switchToOverview()
@@ -84,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 = false, portraitPosTop = false)
+        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
 
+    @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        secondaryApp, landscapePosLeft = true, portraitPosTop = true)
+        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)
@@ -185,7 +176,6 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                repetitions = SplitScreenHelper.TEST_REPETITIONS,
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
                 supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
index b29c436..7cbace5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/ShellTaskOrganizerTests.java
@@ -16,6 +16,8 @@
 
 package com.android.wm.shell;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
@@ -637,26 +639,22 @@
     }
 
     @Test
-    public void testPrepareClearBoundsForTasks() {
-        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED);
-        task1.displayId = 1;
+    public void testPrepareClearBoundsForStandardTasks() {
         MockToken token1 = new MockToken();
-        task1.token = token1.token();
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1);
         mOrganizer.onTaskAppeared(task1, null);
 
-        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED);
-        task2.displayId = 1;
         MockToken token2 = new MockToken();
-        task2.token = token2.token();
+        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2);
         mOrganizer.onTaskAppeared(task2, null);
 
-        RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED);
-        otherDisplayTask.displayId = 2;
         MockToken otherDisplayToken = new MockToken();
-        otherDisplayTask.token = otherDisplayToken.token();
+        RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_UNDEFINED,
+                otherDisplayToken);
+        otherDisplayTask.displayId = 2;
         mOrganizer.onTaskAppeared(otherDisplayTask, null);
 
-        WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForTasks(1);
+        WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1);
 
         assertEquals(wct.getChanges().size(), 2);
         Change boundsChange1 = wct.getChanges().get(token1.binder());
@@ -673,26 +671,40 @@
     }
 
     @Test
-    public void testPrepareClearFreeformForTasks() {
-        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM);
-        task1.displayId = 1;
+    public void testPrepareClearBoundsForStandardTasks_onlyClearActivityTypeStandard() {
         MockToken token1 = new MockToken();
-        task1.token = token1.token();
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_UNDEFINED, token1);
         mOrganizer.onTaskAppeared(task1, null);
 
-        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW);
-        task2.displayId = 1;
         MockToken token2 = new MockToken();
-        task2.token = token2.token();
+        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_UNDEFINED, token2);
+        task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
         mOrganizer.onTaskAppeared(task2, null);
 
-        RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM);
-        otherDisplayTask.displayId = 2;
+        WindowContainerTransaction wct = mOrganizer.prepareClearBoundsForStandardTasks(1);
+
+        // Only clear bounds for task1
+        assertEquals(1, wct.getChanges().size());
+        assertNotNull(wct.getChanges().get(token1.binder()));
+    }
+
+    @Test
+    public void testPrepareClearFreeformForStandardTasks() {
+        MockToken token1 = new MockToken();
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1);
+        mOrganizer.onTaskAppeared(task1, null);
+
+        MockToken token2 = new MockToken();
+        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_MULTI_WINDOW, token2);
+        mOrganizer.onTaskAppeared(task2, null);
+
         MockToken otherDisplayToken = new MockToken();
-        otherDisplayTask.token = otherDisplayToken.token();
+        RunningTaskInfo otherDisplayTask = createTaskInfo(3, WINDOWING_MODE_FREEFORM,
+                otherDisplayToken);
+        otherDisplayTask.displayId = 2;
         mOrganizer.onTaskAppeared(otherDisplayTask, null);
 
-        WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForTasks(1);
+        WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1);
 
         // Only task with freeform windowing mode and the right display should be updated
         assertEquals(wct.getChanges().size(), 1);
@@ -701,6 +713,24 @@
         assertEquals(wmModeChange1.getWindowingMode(), WINDOWING_MODE_UNDEFINED);
     }
 
+    @Test
+    public void testPrepareClearFreeformForStandardTasks_onlyClearActivityTypeStandard() {
+        MockToken token1 = new MockToken();
+        RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_FREEFORM, token1);
+        mOrganizer.onTaskAppeared(task1, null);
+
+        MockToken token2 = new MockToken();
+        RunningTaskInfo task2 = createTaskInfo(2, WINDOWING_MODE_FREEFORM, token2);
+        task2.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_HOME);
+        mOrganizer.onTaskAppeared(task2, null);
+
+        WindowContainerTransaction wct = mOrganizer.prepareClearFreeformForStandardTasks(1);
+
+        // Only clear freeform for task1
+        assertEquals(1, wct.getChanges().size());
+        assertNotNull(wct.getChanges().get(token1.binder()));
+    }
+
     private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
         RunningTaskInfo taskInfo = new RunningTaskInfo();
         taskInfo.taskId = taskId;
@@ -708,6 +738,14 @@
         return taskInfo;
     }
 
+    private static RunningTaskInfo createTaskInfo(int taskId, int windowingMode, MockToken token) {
+        RunningTaskInfo taskInfo = createTaskInfo(taskId, windowingMode);
+        taskInfo.displayId = 1;
+        taskInfo.token = token.token();
+        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+        return taskInfo;
+    }
+
     private static class MockToken {
         private final WindowContainerToken mToken;
         private final IBinder mBinder;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
index 95725bb..695550d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitLayoutTests.java
@@ -159,7 +159,8 @@
     }
 
     private void waitDividerFlingFinished() {
-        verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), mRunnableCaptor.capture());
+        verify(mSplitLayout).flingDividePosition(anyInt(), anyInt(), anyInt(),
+                mRunnableCaptor.capture());
         mRunnableCaptor.getValue().run();
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
index 58f20da..ef532e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
@@ -88,8 +88,8 @@
         WindowContainerTransaction taskWct = new WindowContainerTransaction();
         MockToken taskMockToken = new MockToken();
         taskWct.setWindowingMode(taskMockToken.token(), WINDOWING_MODE_UNDEFINED);
-        when(mShellTaskOrganizer.prepareClearFreeformForTasks(mContext.getDisplayId())).thenReturn(
-                taskWct);
+        when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(
+                mContext.getDisplayId())).thenReturn(taskWct);
 
         // Create a fake WCT to simulate setting display windowing mode to freeform
         WindowContainerTransaction displayWct = new WindowContainerTransaction();
@@ -99,7 +99,7 @@
                 WINDOWING_MODE_FREEFORM)).thenReturn(displayWct);
 
         // The test
-        mController.updateDesktopModeEnabled(true);
+        mController.updateDesktopModeActive(true);
 
         ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
                 WindowContainerTransaction.class);
@@ -126,15 +126,15 @@
         WindowContainerTransaction taskWmWct = new WindowContainerTransaction();
         MockToken taskWmMockToken = new MockToken();
         taskWmWct.setWindowingMode(taskWmMockToken.token(), WINDOWING_MODE_UNDEFINED);
-        when(mShellTaskOrganizer.prepareClearFreeformForTasks(mContext.getDisplayId())).thenReturn(
-                taskWmWct);
+        when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(
+                mContext.getDisplayId())).thenReturn(taskWmWct);
 
         // Create a fake WCT to simulate clearing task bounds
         WindowContainerTransaction taskBoundsWct = new WindowContainerTransaction();
         MockToken taskBoundsMockToken = new MockToken();
         taskBoundsWct.setBounds(taskBoundsMockToken.token(), null);
-        when(mShellTaskOrganizer.prepareClearBoundsForTasks(mContext.getDisplayId())).thenReturn(
-                taskBoundsWct);
+        when(mShellTaskOrganizer.prepareClearBoundsForStandardTasks(
+                mContext.getDisplayId())).thenReturn(taskBoundsWct);
 
         // Create a fake WCT to simulate setting display windowing mode to fullscreen
         WindowContainerTransaction displayWct = new WindowContainerTransaction();
@@ -144,7 +144,7 @@
                 WINDOWING_MODE_FULLSCREEN)).thenReturn(displayWct);
 
         // The test
-        mController.updateDesktopModeEnabled(false);
+        mController.updateDesktopModeActive(false);
 
         ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
                 WindowContainerTransaction.class);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
index 0059846..262e429 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipBoundsAlgorithmTest.java
@@ -64,7 +64,7 @@
         initializeMockResources();
         mPipBoundsState = new PipBoundsState(mContext);
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
-                new PipSnapAlgorithm());
+                new PipSnapAlgorithm(), new PipKeepClearAlgorithm() {});
 
         mPipBoundsState.setDisplayLayout(
                 new DisplayLayout(mDefaultDisplayInfo, mContext.getResources(), true, true));
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
index 579638d..9088077 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/PipTaskOrganizerTest.java
@@ -98,7 +98,7 @@
         mPipBoundsState = new PipBoundsState(mContext);
         mPipTransitionState = new PipTransitionState();
         mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState,
-                new PipSnapAlgorithm());
+                new PipSnapAlgorithm(), new PipKeepClearAlgorithm() {});
         mMainExecutor = new TestShellExecutor();
         mPipTaskOrganizer = new PipTaskOrganizer(mContext,
                 mMockSyncTransactionQueue, mPipTransitionState, mPipBoundsState,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
similarity index 64%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
rename to libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
index e0f7e35..4d7e9e4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipKeepClearAlgorithmTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithmTest.java
@@ -34,61 +34,61 @@
 import java.util.Set;
 
 /**
- * Unit tests against {@link PipKeepClearAlgorithm}.
+ * Unit tests against {@link PhonePipKeepClearAlgorithm}.
  */
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class PipKeepClearAlgorithmTest extends ShellTestCase {
+public class PhonePipKeepClearAlgorithmTest extends ShellTestCase {
 
-    private PipKeepClearAlgorithm mPipKeepClearAlgorithm;
+    private PhonePipKeepClearAlgorithm mPipKeepClearAlgorithm;
     private static final Rect DISPLAY_BOUNDS = new Rect(0, 0, 1000, 1000);
 
     @Before
     public void setUp() throws Exception {
-        mPipKeepClearAlgorithm = new PipKeepClearAlgorithm();
+        mPipKeepClearAlgorithm = new PhonePipKeepClearAlgorithm(mContext);
     }
 
     @Test
-    public void adjust_withCollidingRestrictedKeepClearAreas_movesBounds() {
+    public void findUnoccludedPosition_withCollidingRestrictedKeepClearArea_movesBounds() {
         final Rect inBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(50, 50, 150, 150);
 
-        final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
-                Set.of(), DISPLAY_BOUNDS);
+        final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds,
+                Set.of(keepClearRect), Set.of(), DISPLAY_BOUNDS);
 
         assertFalse(outBounds.contains(keepClearRect));
     }
 
     @Test
-    public void adjust_withNonCollidingRestrictedKeepClearAreas_boundsDoNotChange() {
+    public void findUnoccludedPosition_withNonCollidingRestrictedKeepClearArea_boundsUnchanged() {
         final Rect inBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(100, 100, 150, 150);
 
-        final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(keepClearRect),
-                Set.of(), DISPLAY_BOUNDS);
+        final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds,
+                Set.of(keepClearRect), Set.of(), DISPLAY_BOUNDS);
 
         assertEquals(inBounds, outBounds);
     }
 
     @Test
-    public void adjust_withCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+    public void findUnoccludedPosition_withCollidingUnrestrictedKeepClearArea_moveBounds() {
         // TODO(b/183746978): update this test to accommodate for the updated algorithm
         final Rect inBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(50, 50, 150, 150);
 
-        final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+        final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds, Set.of(),
                 Set.of(keepClearRect), DISPLAY_BOUNDS);
 
-        assertEquals(inBounds, outBounds);
+        assertFalse(outBounds.contains(keepClearRect));
     }
 
     @Test
-    public void adjust_withNonCollidingUnrestrictedKeepClearAreas_boundsDoNotChange() {
+    public void findUnoccludedPosition_withNonCollidingUnrestrictedKeepClearArea_boundsUnchanged() {
         final Rect inBounds = new Rect(0, 0, 100, 100);
         final Rect keepClearRect = new Rect(100, 100, 150, 150);
 
-        final Rect outBounds = mPipKeepClearAlgorithm.adjust(inBounds, Set.of(),
+        final Rect outBounds = mPipKeepClearAlgorithm.findUnoccludedPosition(inBounds, Set.of(),
                 Set.of(keepClearRect), DISPLAY_BOUNDS);
 
         assertEquals(inBounds, outBounds);
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 eb5726b..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;
@@ -64,6 +65,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.util.Optional;
@@ -85,7 +87,7 @@
     @Mock private PhonePipMenuController mMockPhonePipMenuController;
     @Mock private PipAppOpsListener mMockPipAppOpsListener;
     @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
-    @Mock private PipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
+    @Mock private PhonePipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
     @Mock private PipSnapAlgorithm mMockPipSnapAlgorithm;
     @Mock private PipMediaController mMockPipMediaController;
     @Mock private PipTaskOrganizer mMockPipTaskOrganizer;
@@ -98,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;
@@ -119,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);
@@ -185,8 +188,8 @@
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mPipParamsChangedForwarder,
-                mMockOneHandedController, mMockExecutor));
+                mMockTaskStackListener, mMockPipParamsChangedForwarder,
+                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor));
     }
 
     @Test
@@ -267,7 +270,20 @@
     }
 
     @Test
-    public void onKeepClearAreasChanged_updatesPipBoundsState() {
+    public void onKeepClearAreasChanged_featureDisabled_pipBoundsStateDoesntChange() {
+        final int displayId = 1;
+        final Rect keepClearArea = new Rect(0, 0, 10, 10);
+        when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId);
+
+        mPipController.mDisplaysChangedListener.onKeepClearAreasChanged(
+                displayId, Set.of(keepClearArea), Set.of());
+
+        verify(mMockPipBoundsState, never()).setKeepClearAreas(Mockito.anySet(), Mockito.anySet());
+    }
+
+    @Test
+    public void onKeepClearAreasChanged_featureEnabled_updatesPipBoundsState() {
+        mPipController.setEnablePipKeepClearAlgorithm(true);
         final int displayId = 1;
         final Rect keepClearArea = new Rect(0, 0, 10, 10);
         when(mMockPipBoundsState.getDisplayId()).thenReturn(displayId);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
index dd10aa7..dba037d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipResizeGestureHandlerTest.java
@@ -36,6 +36,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
@@ -87,8 +88,10 @@
         MockitoAnnotations.initMocks(this);
         mPipBoundsState = new PipBoundsState(mContext);
         final PipSnapAlgorithm pipSnapAlgorithm = new PipSnapAlgorithm();
+        final PipKeepClearAlgorithm pipKeepClearAlgorithm =
+                new PipKeepClearAlgorithm() {};
         final PipBoundsAlgorithm pipBoundsAlgorithm = new PipBoundsAlgorithm(mContext,
-                mPipBoundsState, pipSnapAlgorithm);
+                mPipBoundsState, pipSnapAlgorithm, pipKeepClearAlgorithm);
         final PipMotionHelper motionHelper = new PipMotionHelper(mContext, mPipBoundsState,
                 mPipTaskOrganizer, mPhonePipMenuController, pipSnapAlgorithm,
                 mMockPipTransitionController, mFloatingContentCoordinator);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
index ecefd89..474d6aa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipTouchHandlerTest.java
@@ -34,6 +34,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
+import com.android.wm.shell.pip.PipKeepClearAlgorithm;
 import com.android.wm.shell.pip.PipSnapAlgorithm;
 import com.android.wm.shell.pip.PipTaskOrganizer;
 import com.android.wm.shell.pip.PipTransitionController;
@@ -104,7 +105,8 @@
         MockitoAnnotations.initMocks(this);
         mPipBoundsState = new PipBoundsState(mContext);
         mPipSnapAlgorithm = new PipSnapAlgorithm();
-        mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm);
+        mPipBoundsAlgorithm = new PipBoundsAlgorithm(mContext, mPipBoundsState, mPipSnapAlgorithm,
+                new PipKeepClearAlgorithm() {});
         PipMotionHelper pipMotionHelper = new PipMotionHelper(mContext, mPipBoundsState,
                 mPipTaskOrganizer, mPhonePipMenuController, mPipSnapAlgorithm,
                 mMockPipTransitionController, mFloatingContentCoordinator);
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..ea9390e 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());
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index e11be31..ab6ac94 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.argThat;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.same;
@@ -59,6 +60,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 
 import java.util.ArrayList;
@@ -96,6 +98,8 @@
     @Mock
     private WindowContainerTransaction mMockWindowContainerTransaction;
 
+    private final List<SurfaceControl.Transaction> mMockSurfaceControlTransactions =
+            new ArrayList<>();
     private final List<SurfaceControl.Builder> mMockSurfaceControlBuilders = new ArrayList<>();
     private SurfaceControl.Transaction mMockSurfaceControlStartT;
     private SurfaceControl.Transaction mMockSurfaceControlFinishT;
@@ -123,6 +127,10 @@
         final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
                 createMockSurfaceControlBuilder(taskBackgroundSurface);
         mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);
+        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder captionContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(captionContainerSurface);
+        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
                 new ActivityManager.TaskDescription.Builder()
@@ -147,6 +155,7 @@
 
         verify(decorContainerSurfaceBuilder, never()).build();
         verify(taskBackgroundSurfaceBuilder, never()).build();
+        verify(captionContainerSurfaceBuilder, never()).build();
         verify(mMockSurfaceControlViewHostFactory, never()).create(any(), any(), any());
 
         verify(mMockSurfaceControlFinishT).hide(taskSurface);
@@ -168,6 +177,10 @@
         final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
                 createMockSurfaceControlBuilder(taskBackgroundSurface);
         mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);
+        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder captionContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(captionContainerSurface);
+        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
 
         final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
                 new ActivityManager.TaskDescription.Builder()
@@ -205,6 +218,12 @@
         verify(mMockSurfaceControlStartT).setLayer(taskBackgroundSurface, -1);
         verify(mMockSurfaceControlStartT).show(taskBackgroundSurface);
 
+        verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
+        verify(captionContainerSurfaceBuilder).setContainerLayer();
+        verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
+        verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
+        verify(mMockSurfaceControlStartT).show(captionContainerSurface);
+
         verify(mMockSurfaceControlViewHostFactory).create(any(), eq(defaultDisplay), any());
         verify(mMockSurfaceControlViewHost)
                 .setView(same(mMockView),
@@ -245,6 +264,13 @@
         final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
                 createMockSurfaceControlBuilder(taskBackgroundSurface);
         mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);
+        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder captionContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(captionContainerSurface);
+        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+        mMockSurfaceControlTransactions.add(t);
 
         final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
                 new ActivityManager.TaskDescription.Builder()
@@ -268,17 +294,19 @@
         windowDecor.relayout(taskInfo);
 
         verify(mMockSurfaceControlViewHost, never()).release();
-        verify(decorContainerSurface, never()).release();
-        verify(taskBackgroundSurface, never()).release();
+        verify(t, never()).apply();
         verify(mMockWindowContainerTransaction, never())
                 .removeInsetsProvider(eq(taskInfo.token), any());
 
         taskInfo.isVisible = false;
         windowDecor.relayout(taskInfo);
 
-        verify(mMockSurfaceControlViewHost).release();
-        verify(decorContainerSurface).release();
-        verify(taskBackgroundSurface).release();
+        final InOrder releaseOrder = inOrder(t, mMockSurfaceControlViewHost);
+        releaseOrder.verify(mMockSurfaceControlViewHost).release();
+        releaseOrder.verify(t).remove(captionContainerSurface);
+        releaseOrder.verify(t).remove(decorContainerSurface);
+        releaseOrder.verify(t).remove(taskBackgroundSurface);
+        releaseOrder.verify(t).apply();
         verify(mMockWindowContainerTransaction).removeInsetsProvider(eq(taskInfo.token), any());
     }
 
@@ -330,21 +358,30 @@
     private TestWindowDecoration createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
         return new TestWindowDecoration(mContext, mMockDisplayController, mMockShellTaskOrganizer,
-                taskInfo, testSurface, new MockSurfaceControlBuilderSupplier(),
+                taskInfo, testSurface,
+                new MockObjectSupplier<>(mMockSurfaceControlBuilders,
+                        () -> createMockSurfaceControlBuilder(mock(SurfaceControl.class))),
+                new MockObjectSupplier<>(mMockSurfaceControlTransactions,
+                        () -> mock(SurfaceControl.Transaction.class)),
                 () -> mMockWindowContainerTransaction, mMockSurfaceControlViewHostFactory);
     }
 
-    private class MockSurfaceControlBuilderSupplier implements Supplier<SurfaceControl.Builder> {
+    private class MockObjectSupplier<T> implements Supplier<T> {
+        private final List<T> mObjects;
+        private final Supplier<T> mDefaultSupplier;
         private int mNumOfCalls = 0;
 
+        private MockObjectSupplier(List<T> objects, Supplier<T> defaultSupplier) {
+            mObjects = objects;
+            mDefaultSupplier = defaultSupplier;
+        }
+
         @Override
-        public SurfaceControl.Builder get() {
-            final SurfaceControl.Builder builder =
-                    mNumOfCalls < mMockSurfaceControlBuilders.size()
-                            ? mMockSurfaceControlBuilders.get(mNumOfCalls)
-                            : createMockSurfaceControlBuilder(mock(SurfaceControl.class));
+        public T get() {
+            final T mock = mNumOfCalls < mObjects.size()
+                    ? mObjects.get(mNumOfCalls) : mDefaultSupplier.get();
             ++mNumOfCalls;
-            return builder;
+            return mock;
         }
     }
 
@@ -362,11 +399,12 @@
                 ShellTaskOrganizer taskOrganizer, ActivityManager.RunningTaskInfo taskInfo,
                 SurfaceControl taskSurface,
                 Supplier<SurfaceControl.Builder> surfaceControlBuilderSupplier,
+                Supplier<SurfaceControl.Transaction> surfaceControlTransactionSupplier,
                 Supplier<WindowContainerTransaction> windowContainerTransactionSupplier,
                 SurfaceControlViewHostFactory surfaceControlViewHostFactory) {
             super(context, displayController, taskOrganizer, taskInfo, taskSurface,
-                    surfaceControlBuilderSupplier, windowContainerTransactionSupplier,
-                    surfaceControlViewHostFactory);
+                    surfaceControlBuilderSupplier, surfaceControlTransactionSupplier,
+                    windowContainerTransactionSupplier, surfaceControlViewHostFactory);
         }
 
         @Override
diff --git a/libs/dream/lowlight/Android.bp b/libs/dream/lowlight/Android.bp
new file mode 100644
index 0000000..5b5b0f0
--- /dev/null
+++ b/libs/dream/lowlight/Android.bp
@@ -0,0 +1,47 @@
+// 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "low_light_dream_lib-sources",
+    srcs: [
+        "src/**/*.java",
+    ],
+    path: "src",
+}
+
+android_library {
+    name: "LowLightDreamLib",
+    srcs: [
+        ":low_light_dream_lib-sources",
+    ],
+    resource_dirs: [
+        "res",
+    ],
+    static_libs: [
+        "androidx.arch.core_core-runtime",
+        "dagger2",
+        "jsr330",
+    ],
+    manifest: "AndroidManifest.xml",
+    plugins: ["dagger2-compiler"],
+}
diff --git a/libs/dream/lowlight/AndroidManifest.xml b/libs/dream/lowlight/AndroidManifest.xml
new file mode 100644
index 0000000..a8d9526
--- /dev/null
+++ b/libs/dream/lowlight/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest package="com.android.dream.lowlight" />
diff --git a/libs/dream/lowlight/res/values/config.xml b/libs/dream/lowlight/res/values/config.xml
new file mode 100644
index 0000000..70fe073
--- /dev/null
+++ b/libs/dream/lowlight/res/values/config.xml
@@ -0,0 +1,20 @@
+<?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>
+    <!-- The dream component used when the device is low light environment. -->
+    <string translatable="false" name="config_lowLightDreamComponent"/>
+</resources>
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
new file mode 100644
index 0000000..5ecec4d
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/LowLightDreamManager.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dream.lowlight;
+
+import static com.android.dream.lowlight.dagger.LowLightDreamModule.LOW_LIGHT_DREAM_COMPONENT;
+
+import android.annotation.IntDef;
+import android.annotation.RequiresPermission;
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * Maintains the ambient light mode of the environment the device is in, and sets a low light dream
+ * component, if present, as the system dream when the ambient light mode is low light.
+ *
+ * @hide
+ */
+public final class LowLightDreamManager {
+    private static final String TAG = "LowLightDreamManager";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "AMBIENT_LIGHT_MODE_" }, value = {
+            AMBIENT_LIGHT_MODE_UNKNOWN,
+            AMBIENT_LIGHT_MODE_REGULAR,
+            AMBIENT_LIGHT_MODE_LOW_LIGHT
+    })
+    public @interface AmbientLightMode {}
+
+    /**
+     * Constant for ambient light mode being unknown.
+     * @hide
+     */
+    public static final int AMBIENT_LIGHT_MODE_UNKNOWN = 0;
+
+    /**
+     * Constant for ambient light mode being regular / bright.
+     * @hide
+     */
+    public static final int AMBIENT_LIGHT_MODE_REGULAR = 1;
+
+    /**
+     * Constant for ambient light mode being low light / dim.
+     * @hide
+     */
+    public static final int AMBIENT_LIGHT_MODE_LOW_LIGHT = 2;
+
+    private final DreamManager mDreamManager;
+
+    @Nullable
+    private final ComponentName mLowLightDreamComponent;
+
+    private int mAmbientLightMode = AMBIENT_LIGHT_MODE_UNKNOWN;
+
+    @Inject
+    public LowLightDreamManager(
+            DreamManager dreamManager,
+            @Named(LOW_LIGHT_DREAM_COMPONENT) @Nullable ComponentName lowLightDreamComponent) {
+        mDreamManager = dreamManager;
+        mLowLightDreamComponent = lowLightDreamComponent;
+    }
+
+    /**
+     * Sets the current ambient light mode.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
+    public void setAmbientLightMode(@AmbientLightMode int ambientLightMode) {
+        if (mLowLightDreamComponent == null) {
+            if (DEBUG) {
+                Log.d(TAG, "ignore ambient light mode change because low light dream component "
+                        + "is empty");
+            }
+            return;
+        }
+
+        if (mAmbientLightMode == ambientLightMode) {
+            return;
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "ambient light mode changed from " + mAmbientLightMode + " to "
+                    + ambientLightMode);
+        }
+
+        mAmbientLightMode = ambientLightMode;
+
+        mDreamManager.setSystemDreamComponent(mAmbientLightMode == AMBIENT_LIGHT_MODE_LOW_LIGHT
+                ? mLowLightDreamComponent : null);
+    }
+}
diff --git a/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java
new file mode 100644
index 0000000..c183a04
--- /dev/null
+++ b/libs/dream/lowlight/src/com/android/dream/lowlight/dagger/LowLightDreamModule.java
@@ -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.dream.lowlight.dagger;
+
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.content.Context;
+
+import androidx.annotation.Nullable;
+
+import com.android.dream.lowlight.R;
+
+import javax.inject.Named;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger module for low light dream.
+ *
+ * @hide
+ */
+@Module
+public interface LowLightDreamModule {
+    String LOW_LIGHT_DREAM_COMPONENT = "low_light_dream_component";
+
+    /**
+     * Provides dream manager.
+     */
+    @Provides
+    static DreamManager providesDreamManager(Context context) {
+        return context.getSystemService(DreamManager.class);
+    }
+
+    /**
+     * Provides the component name of the low light dream, or null if not configured.
+     */
+    @Provides
+    @Named(LOW_LIGHT_DREAM_COMPONENT)
+    @Nullable
+    static ComponentName providesLowLightDreamComponent(Context context) {
+        final String lowLightDreamComponent = context.getResources().getString(
+                R.string.config_lowLightDreamComponent);
+        return lowLightDreamComponent.isEmpty() ? null
+                : ComponentName.unflattenFromString(lowLightDreamComponent);
+    }
+}
diff --git a/libs/dream/lowlight/tests/Android.bp b/libs/dream/lowlight/tests/Android.bp
new file mode 100644
index 0000000..bd6f05e
--- /dev/null
+++ b/libs/dream/lowlight/tests/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "LowLightDreamTests",
+    srcs: [
+        "**/*.java",
+    ],
+    static_libs: [
+        "LowLightDreamLib",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "frameworks-base-testutils",
+        "junit",
+        "mockito-target-extended-minus-junit4",
+        "platform-test-annotations",
+        "testables",
+        "truth-prebuilt",
+    ],
+    libs: [
+        "android.test.mock",
+        "android.test.base",
+        "android.test.runner",
+    ],
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+}
diff --git a/libs/dream/lowlight/tests/AndroidManifest.xml b/libs/dream/lowlight/tests/AndroidManifest.xml
new file mode 100644
index 0000000..abb71fb
--- /dev/null
+++ b/libs/dream/lowlight/tests/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.dream.lowlight.tests">
+
+    <application android:debuggable="true" android:largeHeap="true">
+        <uses-library android:name="android.test.mock" />
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:label="Tests for LowLightDreamLib"
+        android:targetPackage="com.android.dream.lowlight.tests">
+    </instrumentation>
+
+</manifest>
diff --git a/libs/dream/lowlight/tests/AndroidTest.xml b/libs/dream/lowlight/tests/AndroidTest.xml
new file mode 100644
index 0000000..1080033
--- /dev/null
+++ b/libs/dream/lowlight/tests/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<configuration description="Runs Tests for LowLightDreamLib">
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
+        <option name="test-file-name" value="LowLightDreamTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="framework-base-presubmit" />
+    <option name="test-tag" value="LowLightDreamLibTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.dream.lowlight.tests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
new file mode 100644
index 0000000..91a170f
--- /dev/null
+++ b/libs/dream/lowlight/tests/src/com.android.dream.lowlight/LowLightDreamManagerTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.dream.lowlight;
+
+import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_LOW_LIGHT;
+import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_REGULAR;
+import static com.android.dream.lowlight.LowLightDreamManager.AMBIENT_LIGHT_MODE_UNKNOWN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.DreamManager;
+import android.content.ComponentName;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+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)
+public class LowLightDreamManagerTest {
+    @Mock
+    private DreamManager mDreamManager;
+
+    @Mock
+    private ComponentName mDreamComponent;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void setAmbientLightMode_lowLight_setSystemDream() {
+        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+                mDreamComponent);
+
+        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+
+        verify(mDreamManager).setSystemDreamComponent(mDreamComponent);
+    }
+
+    @Test
+    public void setAmbientLightMode_regularLight_clearSystemDream() {
+        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+                mDreamComponent);
+
+        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_REGULAR);
+
+        verify(mDreamManager).setSystemDreamComponent(null);
+    }
+
+    @Test
+    public void setAmbientLightMode_defaultUnknownMode_clearSystemDream() {
+        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+                mDreamComponent);
+
+        // Set to low light first.
+        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+        clearInvocations(mDreamManager);
+
+        // Return to default unknown mode.
+        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_UNKNOWN);
+
+        verify(mDreamManager).setSystemDreamComponent(null);
+    }
+
+    @Test
+    public void setAmbientLightMode_dreamComponentNotSet_doNothing() {
+        final LowLightDreamManager lowLightDreamManager = new LowLightDreamManager(mDreamManager,
+                null /*dream component*/);
+
+        lowLightDreamManager.setAmbientLightMode(AMBIENT_LIGHT_MODE_LOW_LIGHT);
+
+        verify(mDreamManager, never()).setSystemDreamComponent(any());
+    }
+}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 88f73d6..b11e542 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -93,6 +93,10 @@
 
 cc_defaults {
     name: "hwui_static_deps",
+    defaults: [
+        "android.hardware.graphics.common-ndk_shared",
+        "android.hardware.graphics.composer3-ndk_shared",
+    ],
     shared_libs: [
         "libbase",
         "libharfbuzz_ng",
@@ -106,9 +110,7 @@
     target: {
         android: {
             shared_libs: [
-                "android.hardware.graphics.common-V3-ndk",
                 "[email protected]",
-                "android.hardware.graphics.composer3-V1-ndk",
                 "liblog",
                 "libcutils",
                 "libutils",
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 023d6bf..397975d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -57,6 +57,49 @@
 
 using uirenderer::PaintUtils;
 
+class SkiaCanvas::Clip {
+public:
+    Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
+            : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
+    Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m)
+            : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
+    Clip(const SkPath& path, SkClipOp op, const SkMatrix& m)
+            : mType(Type::Path), mOp(op), mMatrix(m), mPath(std::in_place, path) {}
+
+    void apply(SkCanvas* canvas) const {
+        canvas->setMatrix(mMatrix);
+        switch (mType) {
+            case Type::Rect:
+                // Don't anti-alias rectangular clips
+                canvas->clipRect(mRRect.rect(), mOp, false);
+                break;
+            case Type::RRect:
+                // Ensure rounded rectangular clips are anti-aliased
+                canvas->clipRRect(mRRect, mOp, true);
+                break;
+            case Type::Path:
+                // Ensure path clips are anti-aliased
+                canvas->clipPath(mPath.value(), mOp, true);
+                break;
+        }
+    }
+
+private:
+    enum class Type {
+        Rect,
+        RRect,
+        Path,
+    };
+
+    Type mType;
+    SkClipOp mOp;
+    SkMatrix mMatrix;
+
+    // These are logically a union (tracked separately due to non-POD path).
+    std::optional<SkPath> mPath;
+    SkRRect mRRect;
+};
+
 Canvas* Canvas::create_canvas(const SkBitmap& bitmap) {
     return new SkiaCanvas(bitmap);
 }
@@ -200,49 +243,6 @@
     }
 }
 
-class SkiaCanvas::Clip {
-public:
-    Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
-            : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
-    Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m)
-            : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
-    Clip(const SkPath& path, SkClipOp op, const SkMatrix& m)
-            : mType(Type::Path), mOp(op), mMatrix(m), mPath(std::in_place, path) {}
-
-    void apply(SkCanvas* canvas) const {
-        canvas->setMatrix(mMatrix);
-        switch (mType) {
-            case Type::Rect:
-                // Don't anti-alias rectangular clips
-                canvas->clipRect(mRRect.rect(), mOp, false);
-                break;
-            case Type::RRect:
-                // Ensure rounded rectangular clips are anti-aliased
-                canvas->clipRRect(mRRect, mOp, true);
-                break;
-            case Type::Path:
-                // Ensure path clips are anti-aliased
-                canvas->clipPath(mPath.value(), mOp, true);
-                break;
-        }
-    }
-
-private:
-    enum class Type {
-        Rect,
-        RRect,
-        Path,
-    };
-
-    Type mType;
-    SkClipOp mOp;
-    SkMatrix mMatrix;
-
-    // These are logically a union (tracked separately due to non-POD path).
-    std::optional<SkPath> mPath;
-    SkRRect mRRect;
-};
-
 const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
     const SaveRec* rec = mSaveStack ? static_cast<const SaveRec*>(mSaveStack->back()) : nullptr;
     int currentSaveCount = mCanvas->getSaveCount();
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 62e42b8..19cd7bd 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -53,8 +53,12 @@
 }
 
 MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
-    // TODO: Figure out why this workaround is needed, see b/13913604
-    // In the meantime this matches the behavior of GLRenderer, so it is not a regression
+    // In case the surface was destroyed (e.g. a previous trimMemory call) we
+    // need to recreate it here.
+    if (!isSurfaceReady() && mNativeWindow) {
+        setSurface(mNativeWindow.get(), mSwapBehavior);
+    }
+
     EGLint error = 0;
     if (!mEglManager.makeCurrent(mEglSurface, &error)) {
         return MakeCurrentResult::AlreadyCurrent;
@@ -166,6 +170,9 @@
 }
 
 bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior) {
+    mNativeWindow = surface;
+    mSwapBehavior = swapBehavior;
+
     if (mEglSurface != EGL_NO_SURFACE) {
         mEglManager.destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
@@ -182,7 +189,8 @@
 
     if (mEglSurface != EGL_NO_SURFACE) {
         const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
-        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        const bool isPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        ALOGE_IF(preserveBuffer != isPreserved, "Unable to match the desired swap behavior.");
         return true;
     }
 
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 186998a0..a80c613 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -61,7 +61,8 @@
 private:
     renderthread::EglManager& mEglManager;
     EGLSurface mEglSurface = EGL_NO_SURFACE;
-    bool mBufferPreserved = false;
+    sp<ANativeWindow> mNativeWindow;
+    renderthread::SwapBehavior mSwapBehavior = renderthread::SwapBehavior::kSwap_discardBuffer;
 };
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 53a4c60..f10bca6 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -55,7 +55,12 @@
 }
 
 MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
-    return MakeCurrentResult::AlreadyCurrent;
+    // In case the surface was destroyed (e.g. a previous trimMemory call) we
+    // need to recreate it here.
+    if (!isSurfaceReady() && mNativeWindow) {
+        setSurface(mNativeWindow.get(), SwapBehavior::kSwap_default);
+    }
+    return isContextReady() ? MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
 }
 
 Frame SkiaVulkanPipeline::getFrame() {
@@ -132,7 +137,11 @@
 
 void SkiaVulkanPipeline::onStop() {}
 
-bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior) {
+// We can safely ignore the swap behavior because VkManager will always operate
+// in a mode equivalent to EGLManager::SwapBehavior::kBufferAge
+bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior /*swapBehavior*/) {
+    mNativeWindow = surface;
+
     if (mVkSurface) {
         vulkanManager().destroySurface(mVkSurface);
         mVkSurface = nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index d2bdae5..f3d3613 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -66,6 +66,7 @@
     renderthread::VulkanManager& vulkanManager();
 
     renderthread::VulkanSurface* mVkSurface = nullptr;
+    sp<ANativeWindow> mNativeWindow;
 };
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 60ae604..7419f8f 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -404,7 +404,9 @@
     EXPECT_TRUE(pipeline->isSurfaceReady());
     renderThread.destroyRenderingContext();
     EXPECT_FALSE(pipeline->isSurfaceReady());
-    LOG_ALWAYS_FATAL_IF(pipeline->isSurfaceReady());
+
+    pipeline->makeCurrent();
+    EXPECT_TRUE(pipeline->isSurfaceReady());
 }
 
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) {
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 2b9f159..42b72d4 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -146,4 +146,5 @@
     // used by gts tests to verify whitelists
     String[] getBackgroundThrottlingWhitelist();
     PackageTagsList getIgnoreSettingsAllowlist();
+    PackageTagsList getAdasAllowlist();
 }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index f596502..32015b8 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -504,6 +504,19 @@
     }
 
     /**
+     * Returns ADAS packages and their associated attribution tags.
+     *
+     * @hide
+     */
+    public @NonNull PackageTagsList getAdasAllowlist() {
+        try {
+            return mService.getAdasAllowlist();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the extra location controller package on the device.
      *
      * @hide
diff --git a/media/Android.bp b/media/Android.bp
index 7118afa..e97f077 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -35,8 +35,8 @@
         "aidl/android/media/soundtrigger_middleware/SoundTriggerModuleDescriptor.aidl",
     ],
     imports: [
-        "android.media.audio.common.types",
-        "android.media.soundtrigger.types",
+        "android.media.audio.common.types-V2",
+        "android.media.soundtrigger.types-V1",
         "media_permission-aidl",
     ],
 }
@@ -232,12 +232,12 @@
         },
     },
     imports: [
-        "android.media.audio.common.types",
+        "android.media.audio.common.types-V2",
     ],
     versions_with_info: [
         {
             version: "1",
-            imports: ["android.media.audio.common.types-V1"],
+            imports: ["android.media.audio.common.types-V2"],
         },
     ],
 
diff --git a/media/java/android/media/AudioDeviceVolumeManager.java b/media/java/android/media/AudioDeviceVolumeManager.java
index c708876..40f6dc5 100644
--- a/media/java/android/media/AudioDeviceVolumeManager.java
+++ b/media/java/android/media/AudioDeviceVolumeManager.java
@@ -21,6 +21,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -39,23 +41,29 @@
  * @hide
  * AudioDeviceVolumeManager provides access to audio device volume control.
  */
+@SystemApi
 public class AudioDeviceVolumeManager {
 
     // define when using Log.*
     //private static final String TAG = "AudioDeviceVolumeManager";
 
-    /** Indicates no special treatment in the handling of the volume adjustment */
+    /** @hide
+     * Indicates no special treatment in the handling of the volume adjustment */
     public static final int ADJUST_MODE_NORMAL = 0;
-    /** Indicates the start of a volume adjustment */
+    /** @hide
+     * Indicates the start of a volume adjustment */
     public static final int ADJUST_MODE_START = 1;
-    /** Indicates the end of a volume adjustment */
+    /** @hide
+     * Indicates the end of a volume adjustment */
     public static final int ADJUST_MODE_END = 2;
 
+    /** @hide */
     @IntDef(flag = false, prefix = "ADJUST_MODE", value = {
             ADJUST_MODE_NORMAL,
             ADJUST_MODE_START,
             ADJUST_MODE_END}
     )
+    /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     public @interface VolumeAdjustmentMode {}
 
@@ -64,7 +72,16 @@
     private final @NonNull String mPackageName;
     private final @Nullable String mAttributionTag;
 
-    public AudioDeviceVolumeManager(Context context) {
+    /**
+     * Constructor
+     * @param context the Context for the device volume operations
+     */
+    @SuppressLint("ManagerConstructor")
+    // reason for suppression: even though the functionality handled by this class is implemented in
+    // AudioService, we want to avoid bloating android.media.AudioManager
+    // with @SystemApi functionality
+    public AudioDeviceVolumeManager(@NonNull Context context) {
+        Objects.requireNonNull(context);
         mPackageName = context.getApplicationContext().getOpPackageName();
         mAttributionTag = context.getApplicationContext().getAttributionTag();
     }
@@ -101,6 +118,7 @@
                 @VolumeAdjustmentMode int mode);
     }
 
+    /** @hide */
     static class ListenerInfo {
         final @NonNull OnAudioDeviceVolumeChangedListener mListener;
         final @NonNull Executor mExecutor;
@@ -127,6 +145,7 @@
     @GuardedBy("mDeviceVolumeListenerLock")
     private DeviceVolumeDispatcherStub mDeviceVolumeDispatcherStub;
 
+    /** @hide */
     final class DeviceVolumeDispatcherStub extends IAudioDeviceVolumeDispatcher.Stub {
         /**
          * Register / unregister the stub
@@ -305,6 +324,7 @@
      * @param vi the volume information, only stream-based volumes are supported
      * @param ada the device for which volume is to be modified
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) {
         try {
@@ -315,6 +335,7 @@
     }
 
     /**
+     * @hide
      * Return human-readable name for volume behavior
      * @param behavior one of the volume behaviors defined in AudioManager
      * @return a string for the given behavior
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 650f360..6764890 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -65,8 +65,6 @@
 
     private static final String TAG = "AudioSystem";
 
-    private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U
-
     // private constructor to prevent instantiating AudioSystem
     private AudioSystem() {
         throw new UnsupportedOperationException("Trying to instantiate AudioSystem");
@@ -293,7 +291,7 @@
             case AUDIO_FORMAT_APTX_HD: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD;
             case AUDIO_FORMAT_LDAC: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
             case AUDIO_FORMAT_LC3: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3;
-            case AUDIO_FORMAT_OPUS: return SOURCE_CODEC_TYPE_OPUS; // TODO update in U
+            case AUDIO_FORMAT_OPUS: return BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS;
             default:
                 Log.e(TAG, "Unknown audio format 0x" + Integer.toHexString(audioFormat)
                         + " for conversion to BT codec");
@@ -336,7 +334,7 @@
                 return AudioSystem.AUDIO_FORMAT_LDAC;
             case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3:
                 return AudioSystem.AUDIO_FORMAT_LC3;
-            case SOURCE_CODEC_TYPE_OPUS: // TODO update in U
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS:
                 return AudioSystem.AUDIO_FORMAT_OPUS;
             default:
                 Log.e(TAG, "Unknown BT codec 0x" + Integer.toHexString(btCodec)
@@ -2385,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 ee2e448..6317320 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -5092,9 +5092,12 @@
             @Nullable Map<String, String> optionalParameters)
             throws NoDrmSchemeException
     {
-        Log.v(TAG, "getKeyRequest: " +
-                " keySetId: " + keySetId + " initData:" + initData + " mimeType: " + mimeType +
-                " keyType: " + keyType + " optionalParameters: " + optionalParameters);
+        Log.v(TAG, "getKeyRequest: "
+                + " keySetId: " + Arrays.toString(keySetId)
+                + " initData:" + Arrays.toString(initData)
+                + " mimeType: " + mimeType
+                + " keyType: " + keyType
+                + " optionalParameters: " + optionalParameters);
 
         synchronized (mDrmLock) {
             if (!mActiveDrmScheme) {
@@ -5153,7 +5156,8 @@
     public byte[] provideKeyResponse(@Nullable byte[] keySetId, @NonNull byte[] response)
             throws NoDrmSchemeException, DeniedByServerException
     {
-        Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response);
+        Log.v(TAG, "provideKeyResponse: keySetId: " + Arrays.toString(keySetId)
+                + " response: " + Arrays.toString(response));
 
         synchronized (mDrmLock) {
 
@@ -5169,8 +5173,9 @@
 
                 byte[] keySetResult = mDrmObj.provideKeyResponse(scope, response);
 
-                Log.v(TAG, "provideKeyResponse: keySetId: " + keySetId + " response: " + response +
-                        " --> " + keySetResult);
+                Log.v(TAG, "provideKeyResponse: keySetId: " + Arrays.toString(keySetId)
+                        + " response: " + Arrays.toString(response)
+                        + " --> " + Arrays.toString(keySetResult));
 
 
                 return keySetResult;
@@ -5197,7 +5202,7 @@
     public void restoreKeys(@NonNull byte[] keySetId)
             throws NoDrmSchemeException
     {
-        Log.v(TAG, "restoreKeys: keySetId: " + keySetId);
+        Log.v(TAG, "restoreKeys: keySetId: " + Arrays.toString(keySetId));
 
         synchronized (mDrmLock) {
 
@@ -5484,7 +5489,8 @@
         // at prepareDrm/openSession rather than getKeyRequest/provideKeyResponse
         try {
             mDrmSessionId = mDrmObj.openSession();
-            Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId=" + mDrmSessionId);
+            Log.v(TAG, "prepareDrm_openSessionStep: mDrmSessionId="
+                    + Arrays.toString(mDrmSessionId));
 
             // Sending it down to native/mediaserver to create the crypto object
             // This call could simply fail due to bad player state, e.g., after start().
@@ -5547,7 +5553,7 @@
                     response = Streams.readFully(connection.getInputStream());
 
                     Log.v(TAG, "HandleProvisioninig: Thread run: response " +
-                            response.length + " " + response);
+                            response.length + " " + Arrays.toString(response));
                 } catch (Exception e) {
                     status = PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR;
                     Log.w(TAG, "HandleProvisioninig: Thread run: connect " + e + " url: " + url);
@@ -5631,8 +5637,9 @@
             return PREPARE_DRM_STATUS_PREPARATION_ERROR;
         }
 
-        Log.v(TAG, "HandleProvisioninig provReq " +
-                " data: " + provReq.getData() + " url: " + provReq.getDefaultUrl());
+        Log.v(TAG, "HandleProvisioninig provReq "
+                + " data: " + Arrays.toString(provReq.getData())
+                + " url: " + provReq.getDefaultUrl());
 
         // networking in a background thread
         mDrmProvisioningInProgress = true;
@@ -5715,7 +5722,8 @@
     private void cleanDrmObj()
     {
         // the caller holds mDrmLock
-        Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj + " mDrmSessionId=" + mDrmSessionId);
+        Log.v(TAG, "cleanDrmObj: mDrmObj=" + mDrmObj
+                + " mDrmSessionId=" + Arrays.toString(mDrmSessionId));
 
         if (mDrmSessionId != null)    {
             mDrmObj.closeSession(mDrmSessionId);
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/VolumeInfo.java b/media/java/android/media/VolumeInfo.java
index c61b0e5..6b4f604 100644
--- a/media/java/android/media/VolumeInfo.java
+++ b/media/java/android/media/VolumeInfo.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.content.Context;
 import android.media.audiopolicy.AudioVolumeGroup;
 import android.os.IBinder;
@@ -32,16 +33,13 @@
 
 /**
  * @hide
- * A class to represent type of volume information.
+ * A class to represent volume information.
  * Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}.
  * Volume index is optional when used to represent a category of volume.
  * Index ranges are supported too, making the representation of volume changes agnostic to the
  * range (e.g. can be used to map BT A2DP absolute volume range to internal range).
- *
- * Note: this class is not yet part of the SystemApi but is intended to be gradually introduced
- *       particularly in parts of the audio framework that suffer from code ambiguity when
- *       dealing with different volume ranges / units.
  */
+@SystemApi
 public final class VolumeInfo implements Parcelable {
     private static final String TAG = "VolumeInfo";
 
diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java
index 31d5967..f957498 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategy.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java
@@ -32,6 +32,7 @@
 import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -182,7 +183,7 @@
         AudioProductStrategy thatStrategy = (AudioProductStrategy) o;
 
         return mName == thatStrategy.mName && mId == thatStrategy.mId
-                && mAudioAttributesGroups.equals(thatStrategy.mAudioAttributesGroups);
+                && Arrays.equals(mAudioAttributesGroups, thatStrategy.mAudioAttributesGroups);
     }
 
     /**
@@ -415,7 +416,7 @@
 
             return mVolumeGroupId == thatAag.mVolumeGroupId
                     && mLegacyStreamType == thatAag.mLegacyStreamType
-                    && mAudioAttributes.equals(thatAag.mAudioAttributes);
+                    && Arrays.equals(mAudioAttributes, thatAag.mAudioAttributes);
         }
 
         public int getStreamType() {
diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroup.java b/media/java/android/media/audiopolicy/AudioVolumeGroup.java
index 79be922..d58111d 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java
@@ -114,7 +114,7 @@
         AudioVolumeGroup thatAvg = (AudioVolumeGroup) o;
 
         return mName == thatAvg.mName && mId == thatAvg.mId
-                && mAudioAttributes.equals(thatAvg.mAudioAttributes);
+                && Arrays.equals(mAudioAttributes, thatAvg.mAudioAttributes);
     }
 
     /**
diff --git a/media/java/android/media/metrics/PlaybackMetrics.java b/media/java/android/media/metrics/PlaybackMetrics.java
index e71ee20..51a2c9d 100644
--- a/media/java/android/media/metrics/PlaybackMetrics.java
+++ b/media/java/android/media/metrics/PlaybackMetrics.java
@@ -402,9 +402,10 @@
     @Override
     public int hashCode() {
         return Objects.hash(mMediaDurationMillis, mStreamSource, mStreamType, mPlaybackType,
-                mDrmType, mContentType, mPlayerName, mPlayerVersion, mExperimentIds,
-                mVideoFramesPlayed, mVideoFramesDropped, mAudioUnderrunCount, mNetworkBytesRead,
-                mLocalBytesRead, mNetworkTransferDurationMillis, mDrmSessionId);
+                mDrmType, mContentType, mPlayerName, mPlayerVersion,
+                Arrays.hashCode(mExperimentIds), mVideoFramesPlayed, mVideoFramesDropped,
+                mAudioUnderrunCount, mNetworkBytesRead, mLocalBytesRead,
+                mNetworkTransferDurationMillis, Arrays.hashCode(mDrmSessionId));
     }
 
     @Override
diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl
index 31fb8d0..9bf126b 100644
--- a/media/java/android/media/session/ISession.aidl
+++ b/media/java/android/media/session/ISession.aidl
@@ -35,7 +35,7 @@
     ISessionController getController();
     void setFlags(int flags);
     void setActive(boolean active);
-    void setMediaButtonReceiver(in PendingIntent mbr);
+    void setMediaButtonReceiver(in PendingIntent mbr, String sessionPackageName);
     void setMediaButtonBroadcastReceiver(in ComponentName broadcastReceiver);
     void setLaunchPendingIntent(in PendingIntent pi);
     void destroySession();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 1bd12af..9e265d8 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -286,7 +286,7 @@
     @Deprecated
     public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
         try {
-            mBinder.setMediaButtonReceiver(mbr);
+            mBinder.setMediaButtonReceiver(mbr, mContext.getPackageName());
         } catch (RemoteException e) {
             Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
         }
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index ac5f35f..ecc44f4 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -181,8 +181,11 @@
                     format.get(), AMEDIAFORMAT_KEY_CHANNEL_COUNT, channelCount)) {
                 return UNKNOWN_ERROR;
             }
-            if (!AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_CHANNEL_MASK,
-                    (int32_t*) channelMask)) {
+            int32_t mediaFormatChannelMask;
+            if (AMediaFormat_getInt32(format.get(), AMEDIAFORMAT_KEY_CHANNEL_MASK,
+                    &mediaFormatChannelMask)) {
+                *channelMask = audio_channel_mask_from_media_format_mask(mediaFormatChannelMask);
+            } else {
                 *channelMask = AUDIO_CHANNEL_NONE;
             }
             *sizeInBytes = written;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraErrorCollector.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraErrorCollector.java
index 41914b8..ebf1a75 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraErrorCollector.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraErrorCollector.java
@@ -16,10 +16,6 @@
 
 package com.android.mediaframeworktest.helpers;
 
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.Matcher;
-import org.junit.rules.ErrorCollector;
-
 import android.graphics.Rect;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
@@ -30,6 +26,10 @@
 import android.util.Log;
 import android.util.Size;
 
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Matcher;
+import org.junit.rules.ErrorCollector;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -903,7 +903,7 @@
         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
             return;
         }
-        String reason = "Key " + key.getName() + " value " + value
+        String reason = "Key " + key.getName() + " value " + Arrays.toString(value)
                 + " doesn't contain the expected value " + expected;
         expectContains(reason, value, expected);
     }
@@ -921,7 +921,7 @@
         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
             return;
         }
-        String reason = "Key " + key.getName() + " value " + value
+        String reason = "Key " + key.getName() + " value " + Arrays.toString(value)
                 + " doesn't contain the expected value " + expected;
         expectContains(reason, value, expected);
     }
@@ -939,7 +939,7 @@
         if ((value = expectKeyValueNotNull(characteristics, key)) == null) {
             return;
         }
-        String reason = "Key " + key.getName() + " value " + value
+        String reason = "Key " + key.getName() + " value " + Arrays.toString(value)
                 + " doesn't contain the expected value " + expected;
         expectContains(reason, value, expected);
     }
@@ -960,7 +960,7 @@
 
     public <T> void expectContains(T[] values, T expected) {
         String reason = "Expected value " + expected
-                + " is not contained in the given values " + values;
+                + " is not contained in the given values " + Arrays.toString(values);
         expectContains(reason, values, expected);
     }
 
@@ -996,7 +996,7 @@
 
     public void expectContains(int[] values, int expected) {
         String reason = "Expected value " + expected
-                + " is not contained in the given values " + values;
+                + " is not contained in the given values " + Arrays.toString(values);
         expectContains(reason, values, expected);
     }
 
@@ -1040,7 +1040,7 @@
      */
     public void expectContains(boolean[] values, boolean expected) {
         String reason = "Expected value " + expected
-                + " is not contained in the given values " + values;
+                + " is not contained in the given values " + Arrays.toString(values);
         expectContains(reason, values, expected);
     }
 
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 37c8367..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;
@@ -34,12 +36,10 @@
 import static com.android.mediaroutertest.StubMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
 import static com.android.mediaroutertest.StubMediaRoute2ProviderService.VOLUME_MAX;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
 import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
 
 import android.Manifest;
 import android.app.UiAutomation;
@@ -206,9 +206,8 @@
                 });
 
         mService.addRoutes(routes);
-        assertTrue(
-                "Added routes not found or onRoutesUpdated() never called.",
-                addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertWithMessage("Added routes not found or onRoutesUpdated() never called.")
+                .that(addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         MediaRoute2Info newRoute2 =
                 new MediaRoute2Info.Builder(routes.get(1))
@@ -216,18 +215,16 @@
                         .build();
         routes.set(1, newRoute2);
         mService.addRoute(routes.get(1));
-        assertTrue(
-                "Modified route not found or onRoutesUpdated() never called.",
-                changedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertWithMessage("Modified route not found or onRoutesUpdated() never called.")
+                .that(changedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         List<String> routeIds = new ArrayList<>();
         routeIds.add(routeId0);
         routeIds.add(routeId1);
 
         mService.removeRoutes(routeIds);
-        assertTrue(
-                "Removed routes not found or onRoutesUpdated() never called.",
-                removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertWithMessage("Removed routes not found or onRoutesUpdated() never called.")
+                .that(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
     }
 
     private static boolean checkRoutesMatch(
@@ -242,9 +239,10 @@
             if (matchingRoute == null) {
                 return false;
             }
-            assertTrue(TextUtils.equals(expectedRoute.getName(), matchingRoute.getName()));
-            assertEquals(expectedRoute.getFeatures(), matchingRoute.getFeatures());
-            assertEquals(expectedRoute.getConnectionState(), matchingRoute.getConnectionState());
+            assertThat(TextUtils.equals(expectedRoute.getName(), matchingRoute.getName())).isTrue();
+            assertThat(matchingRoute.getFeatures()).isEqualTo(expectedRoute.getFeatures());
+            assertThat(matchingRoute.getConnectionState())
+                    .isEqualTo(expectedRoute.getConnectionState());
         }
 
         return true;
@@ -288,19 +286,19 @@
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info routeToRemove = routes.get(ROUTE_ID2);
-        assertNotNull(routeToRemove);
+        assertThat(routeToRemove).isNotNull();
 
         mService.removeRoute(ROUTE_ID2);
 
         // Wait until the route is removed.
-        assertTrue(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(removedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         Map<String, MediaRoute2Info> newRoutes = waitAndGetRoutesWithManager(FEATURES_ALL);
-        assertNull(newRoutes.get(ROUTE_ID2));
+        assertThat(newRoutes.get(ROUTE_ID2)).isNull();
 
         // Revert the removal.
         mService.addRoute(routeToRemove);
-        assertTrue(addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(addedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
         mRouter2.unregisterRouteCallback(routeCallback);
     }
 
@@ -318,8 +316,8 @@
             }
         }
 
-        assertEquals(1, routeCount);
-        assertNotNull(routes.get(ROUTE_ID_SPECIAL_FEATURE));
+        assertThat(routeCount).isEqualTo(1);
+        assertThat(routes.get(ROUTE_ID_SPECIAL_FEATURE)).isNotNull();
     }
 
     @Test
@@ -337,7 +335,7 @@
             }
         }
 
-        assertEquals(0, remoteRouteCount);
+        assertThat(remoteRouteCount).isEqualTo(0);
     }
 
     @Test
@@ -355,7 +353,7 @@
             }
         }
 
-        assertTrue(remoteRouteCount > 0);
+        assertThat(remoteRouteCount).isGreaterThan(0);
     }
 
     /**
@@ -384,11 +382,11 @@
         });
 
         MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
-        assertNotNull(routeToSelect);
+        assertThat(routeToSelect).isNotNull();
 
         mManager.selectRoute(mPackageName, routeToSelect);
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertEquals(1, mManager.getRemoteSessions().size());
+        assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        assertThat(mManager.getRemoteSessions()).hasSize(1);
     }
 
     @Test
@@ -410,20 +408,20 @@
             }
         });
 
-        assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
 
         mManager.selectRoute(mPackageName, routeToSelect);
-        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
-        assertEquals(2, sessions.size());
+        assertThat(sessions).hasSize(2);
 
         RoutingSessionInfo sessionInfo = sessions.get(1);
         awaitOnRouteChangedManager(
                 () -> mManager.releaseSession(sessionInfo),
                 ROUTE_ID1,
                 route -> TextUtils.equals(route.getClientPackageName(), null));
-        assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
     }
 
     @Test
@@ -437,7 +435,7 @@
             @Override
             public void onTransferred(RoutingSessionInfo oldSessionInfo,
                     RoutingSessionInfo newSessionInfo) {
-                assertNotNull(newSessionInfo);
+                assertThat(newSessionInfo).isNotNull();
                 onSessionCreatedLatch.countDown();
             }
             @Override
@@ -452,8 +450,8 @@
                 .build();
 
         mManager.transfer(mManager.getSystemRoutingSession(null), unknownRoute);
-        assertFalse(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
-        assertTrue(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
+        assertThat(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
     }
 
     @Test
@@ -463,7 +461,7 @@
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
-        assertNotNull(routeToSelect);
+        assertThat(routeToSelect).isNotNull();
 
         addRouterCallback(new RouteCallback() {});
         addManagerCallback(new MediaRouter2Manager.Callback() {
@@ -481,20 +479,20 @@
             }
         });
 
-        assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
-        assertEquals(1, mRouter2.getControllers().size());
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
+        assertThat(mRouter2.getControllers()).hasSize(1);
 
         mManager.transfer(mManager.getRoutingSessions(mPackageName).get(0), routeToSelect);
-        assertTrue(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
-        assertEquals(2, mManager.getRoutingSessions(mPackageName).size());
-        assertEquals(2, mRouter2.getControllers().size());
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(2);
+        assertThat(mRouter2.getControllers()).hasSize(2);
         mRouter2.getControllers().get(1).release();
 
-        assertTrue(releaseLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(releaseLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
-        assertEquals(1, mRouter2.getControllers().size());
-        assertEquals(1, mManager.getRoutingSessions(mPackageName).size());
+        assertThat(mRouter2.getControllers()).hasSize(1);
+        assertThat(mManager.getRoutingSessions(mPackageName)).hasSize(1);
     }
 
     /**
@@ -511,7 +509,7 @@
             @Override
             public void onTransferred(RoutingSessionInfo oldSessionInfo,
                     RoutingSessionInfo newSessionInfo) {
-                assertNotNull(newSessionInfo);
+                assertThat(newSessionInfo).isNotNull();
                 onSessionCreatedLatch.countDown();
             }
         });
@@ -519,11 +517,11 @@
                 () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
                 ROUTE_ID1,
                 route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
-        assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
 
-        assertEquals(2, sessions.size());
+        assertThat(sessions.size()).isEqualTo(2);
         RoutingSessionInfo sessionInfo = sessions.get(1);
 
         awaitOnRouteChangedManager(
@@ -582,30 +580,33 @@
 
         MediaRoute2Info route1 = routes.get(ROUTE_ID1);
         MediaRoute2Info route2 = routes.get(ROUTE_ID2);
-        assertNotNull(route1);
-        assertNotNull(route2);
+        assertThat(route1).isNotNull();
+        assertThat(route2).isNotNull();
 
         mManager.selectRoute(mPackageName, route1);
-        assertTrue(successLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(successLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
         mManager.selectRoute(mPackageName, route2);
-        assertTrue(successLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(successLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         // onTransferFailed/onSessionReleased should not be called.
-        assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
-        assertFalse(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertThat(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
+        assertThat(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS))
+                .isFalse();
 
-        assertEquals(2, sessions.size());
+        assertThat(sessions.size()).isEqualTo(2);
         List<String> remoteSessionIds = mManager.getRemoteSessions().stream()
                 .map(RoutingSessionInfo::getId)
                 .collect(Collectors.toList());
         // The old session shouldn't appear on the session list.
-        assertFalse(remoteSessionIds.contains(sessions.get(0).getId()));
-        assertTrue(remoteSessionIds.contains(sessions.get(1).getId()));
+        assertThat(remoteSessionIds).doesNotContain(sessions.get(0).getId());
+        assertThat(remoteSessionIds).contains(sessions.get(1).getId());
 
-        assertFalse(serviceOnReleaseSessionLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertThat(serviceOnReleaseSessionLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS))
+                .isFalse();
         mManager.releaseSession(sessions.get(0));
-        assertTrue(serviceOnReleaseSessionLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertFalse(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertThat(serviceOnReleaseSessionLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        assertThat(managerOnSessionReleasedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS))
+                .isFalse();
     }
 
     @Test
@@ -633,9 +634,9 @@
         RoutingSessionInfo targetSession = sessions.get(sessions.size() - 1);
         mManager.transfer(targetSession, routes.get(ROUTE_ID6_TO_BE_IGNORED));
 
-        assertFalse(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
-        assertTrue(onFailedLatch.await(MediaRouter2Manager.TRANSFER_TIMEOUT_MS,
-                TimeUnit.MILLISECONDS));
+        assertThat(onSessionCreatedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
+        assertThat(onFailedLatch.await(MediaRouter2Manager.TRANSFER_TIMEOUT_MS,
+                TimeUnit.MILLISECONDS)).isTrue();
     }
 
     @Test
@@ -647,7 +648,7 @@
                 mManager.getSystemRoutingSession(mPackageName).getSelectedRoutes().get(0));
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL);
         MediaRoute2Info volRoute = routes.get(selectedSystemRouteId);
-        assertNotNull(volRoute);
+        assertThat(volRoute).isNotNull();
 
         int originalVolume = volRoute.getVolume();
         int targetVolume = originalVolume == volRoute.getVolumeMax()
@@ -697,16 +698,16 @@
             @Override
             public void onTransferred(RoutingSessionInfo oldSessionInfo,
                     RoutingSessionInfo newSessionInfo) {
-                assertNotNull(newSessionInfo);
+                assertThat(newSessionInfo).isNotNull();
                 onSessionCreatedLatch.countDown();
             }
         });
 
         mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1));
-        assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName);
-        assertEquals(2, sessions.size());
+        assertThat(sessions).hasSize(2);
 
         // test setSessionVolume
         RoutingSessionInfo sessionInfo = sessions.get(1);
@@ -741,7 +742,7 @@
         try {
             mRouter2.registerControllerCallback(mExecutor, controllerCallback);
             mManager.setSessionVolume(sessionInfo, targetVolume);
-            assertTrue(volumeChangedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertThat(volumeChangedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
         } finally {
             mRouter2.unregisterControllerCallback(controllerCallback);
         }
@@ -768,8 +769,8 @@
 
         addManagerCallback(new MediaRouter2Manager.Callback() {});
         mManager.setRouteVolume(volRoute, 0);
-        assertTrue(onSetRouteVolumeLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertFalse(requestIds.isEmpty());
+        assertThat(onSetRouteVolumeLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        assertThat(requestIds).isNotEmpty();
 
         final int failureReason = REASON_REJECTED;
         final CountDownLatch onRequestFailedLatch = new CountDownLatch(1);
@@ -789,16 +790,17 @@
 
         final long invalidRequestId = REQUEST_ID_NONE;
         mService.notifyRequestFailed(invalidRequestId, failureReason);
-        assertFalse(onRequestFailedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertThat(onRequestFailedLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
 
         final long validRequestId = requestIds.get(0);
         mService.notifyRequestFailed(validRequestId, failureReason);
-        assertTrue(onRequestFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(onRequestFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
         // Test calling notifyRequestFailed() multiple times with the same valid requestId.
         // onRequestFailed() shouldn't be called since the requestId has been already handled.
         mService.notifyRequestFailed(validRequestId, failureReason);
-        assertFalse(onRequestFailedSecondCallLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(onRequestFailedSecondCallLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS))
+                .isFalse();
     }
 
     @Test
@@ -808,9 +810,9 @@
         MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
         MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
 
-        assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
-        assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
-        assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
+        assertThat(fixedVolumeRoute.getVolumeHandling()).isEqualTo(PLAYBACK_VOLUME_FIXED);
+        assertThat(variableVolumeRoute.getVolumeHandling()).isEqualTo(PLAYBACK_VOLUME_VARIABLE);
+        assertThat(variableVolumeRoute.getVolumeMax()).isEqualTo(VOLUME_MAX);
     }
 
     @Test
@@ -819,7 +821,7 @@
         addRouterCallback(new RouteCallback() {});
 
         MediaRoute2Info route = routes.get(ROUTE_ID1);
-        assertNotNull(route);
+        assertThat(route).isNotNull();
 
         final Bundle controllerHints = new Bundle();
         controllerHints.putString(TEST_KEY, TEST_VALUE);
@@ -837,13 +839,13 @@
             @Override
             public void onTransferred(RoutingSessionInfo oldSession,
                     RoutingSessionInfo newSession) {
-                assertTrue(newSession.getSelectedRoutes().contains(route.getId()));
+                assertThat(newSession.getSelectedRoutes()).contains(route.getId());
                 // The StubMediaRoute2ProviderService is supposed to set control hints
                 // with the given controllerHints.
                 Bundle controlHints = newSession.getControlHints();
-                assertNotNull(controlHints);
-                assertTrue(controlHints.containsKey(TEST_KEY));
-                assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY));
+                assertThat(controlHints).isNotNull();
+                assertThat(controlHints).containsKey(TEST_KEY);
+                assertThat(controlHints).string(TEST_KEY).isEqualTo(TEST_VALUE);
 
                 successLatch.countDown();
             }
@@ -857,10 +859,10 @@
 
         mRouter2.setOnGetControllerHintsListener(listener);
         mManager.selectRoute(mPackageName, route);
-        assertTrue(hintLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(hintLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        assertThat(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
 
-        assertFalse(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS));
+        assertThat(failureLatch.await(WAIT_TIME_MS, TimeUnit.MILLISECONDS)).isFalse();
     }
 
     @Test
@@ -885,24 +887,24 @@
             @Override
             public void onTransferred(RoutingSessionInfo oldSessionInfo,
                     RoutingSessionInfo newSessionInfo) {
-                assertNotNull(newSessionInfo);
+                assertThat(newSessionInfo).isNotNull();
                 List<String> selectedRoutes = mManager.getSelectedRoutes(newSessionInfo).stream()
                         .map(MediaRoute2Info::getId)
                         .collect(Collectors.toList());
                 for (MediaRoute2Info selectableRoute :
                         mManager.getSelectableRoutes(newSessionInfo)) {
-                    assertFalse(selectedRoutes.contains(selectableRoute.getId()));
+                    assertThat(selectedRoutes).doesNotContain(selectableRoute.getId());
                 }
                 for (MediaRoute2Info deselectableRoute :
                         mManager.getDeselectableRoutes(newSessionInfo)) {
-                    assertTrue(selectedRoutes.contains(deselectableRoute.getId()));
+                    assertThat(selectedRoutes).contains(deselectableRoute.getId());
                 }
                 onSessionCreatedLatch.countDown();
             }
         });
 
         mManager.selectRoute(mPackageName, routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT));
-        assertTrue(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        assertThat(onSessionCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
     }
 
     Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> routeFeatures)
@@ -984,7 +986,7 @@
         mManager.registerCallback(mExecutor, callback);
         try {
             task.run();
-            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertThat(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
         } finally {
             mManager.unregisterCallback(callback);
         }
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
index 3fe0928..3955ff0 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/RoutingSessionInfoTest.java
@@ -16,8 +16,7 @@
 
 package com.android.mediaroutertest;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static com.google.common.truth.Truth.assertThat;
 
 import android.content.res.Resources;
 import android.media.MediaRoute2Info;
@@ -62,39 +61,39 @@
         RoutingSessionInfo sessionInfoWithProviderId = new RoutingSessionInfo.Builder(sessionInfo)
                 .setProviderId(TEST_PROVIDER_ID).build();
 
-        assertNotEquals(sessionInfo.getSelectedRoutes(),
-                sessionInfoWithProviderId.getSelectedRoutes());
-        assertNotEquals(sessionInfo.getSelectableRoutes(),
-                sessionInfoWithProviderId.getSelectableRoutes());
-        assertNotEquals(sessionInfo.getDeselectableRoutes(),
-                sessionInfoWithProviderId.getDeselectableRoutes());
-        assertNotEquals(sessionInfo.getTransferableRoutes(),
-                sessionInfoWithProviderId.getTransferableRoutes());
+        assertThat(sessionInfoWithProviderId.getSelectedRoutes())
+                .isNotEqualTo(sessionInfo.getSelectedRoutes());
+        assertThat(sessionInfoWithProviderId.getSelectableRoutes())
+                .isNotEqualTo(sessionInfo.getSelectableRoutes());
+        assertThat(sessionInfoWithProviderId.getDeselectableRoutes())
+                .isNotEqualTo(sessionInfo.getDeselectableRoutes());
+        assertThat(sessionInfoWithProviderId.getTransferableRoutes())
+                .isNotEqualTo(sessionInfo.getTransferableRoutes());
 
         RoutingSessionInfo sessionInfoWithOtherProviderId =
                 new RoutingSessionInfo.Builder(sessionInfoWithProviderId)
                         .setProviderId(TEST_OTHER_PROVIDER_ID).build();
 
-        assertNotEquals(sessionInfoWithOtherProviderId.getSelectedRoutes(),
-                sessionInfoWithProviderId.getSelectedRoutes());
-        assertNotEquals(sessionInfoWithOtherProviderId.getSelectableRoutes(),
-                sessionInfoWithProviderId.getSelectableRoutes());
-        assertNotEquals(sessionInfoWithOtherProviderId.getDeselectableRoutes(),
-                sessionInfoWithProviderId.getDeselectableRoutes());
-        assertNotEquals(sessionInfoWithOtherProviderId.getTransferableRoutes(),
-                sessionInfoWithProviderId.getTransferableRoutes());
+        assertThat(sessionInfoWithOtherProviderId.getSelectedRoutes())
+                .isNotEqualTo(sessionInfoWithProviderId.getSelectedRoutes());
+        assertThat(sessionInfoWithOtherProviderId.getSelectableRoutes())
+                .isNotEqualTo(sessionInfoWithProviderId.getSelectableRoutes());
+        assertThat(sessionInfoWithOtherProviderId.getDeselectableRoutes())
+                .isNotEqualTo(sessionInfoWithProviderId.getDeselectableRoutes());
+        assertThat(sessionInfoWithOtherProviderId.getTransferableRoutes())
+                .isNotEqualTo(sessionInfoWithProviderId.getTransferableRoutes());
 
         RoutingSessionInfo sessionInfoWithProviderId2 =
                 new RoutingSessionInfo.Builder(sessionInfoWithProviderId).build();
 
-        assertEquals(sessionInfoWithProviderId2.getSelectedRoutes(),
-                sessionInfoWithProviderId.getSelectedRoutes());
-        assertEquals(sessionInfoWithProviderId2.getSelectableRoutes(),
-                sessionInfoWithProviderId.getSelectableRoutes());
-        assertEquals(sessionInfoWithProviderId2.getDeselectableRoutes(),
-                sessionInfoWithProviderId.getDeselectableRoutes());
-        assertEquals(sessionInfoWithProviderId2.getTransferableRoutes(),
-                sessionInfoWithProviderId.getTransferableRoutes());
+        assertThat(sessionInfoWithProviderId2.getSelectedRoutes())
+                .isEqualTo(sessionInfoWithProviderId.getSelectedRoutes());
+        assertThat(sessionInfoWithProviderId2.getSelectableRoutes())
+                .isEqualTo(sessionInfoWithProviderId.getSelectableRoutes());
+        assertThat(sessionInfoWithProviderId2.getDeselectableRoutes())
+                .isEqualTo(sessionInfoWithProviderId.getDeselectableRoutes());
+        assertThat(sessionInfoWithProviderId2.getTransferableRoutes())
+                .isEqualTo(sessionInfoWithProviderId.getTransferableRoutes());
     }
 
     @Test
@@ -114,6 +113,6 @@
                 ? MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE :
                 MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
 
-        assertEquals(sessionInfo.getVolumeHandling(), expectedResult);
+        assertThat(sessionInfo.getVolumeHandling()).isEqualTo(expectedResult);
     }
 }
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 4aa5bbf..1f96617 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -266,6 +266,7 @@
     ASurfaceTransaction_setEnableBackPressure; # introduced=31
     ASurfaceTransaction_setFrameRate; # introduced=30
     ASurfaceTransaction_setFrameRateWithChangeStrategy; # introduced=31
+    ASurfaceTransaction_clearFrameRate; # introduced=34
     ASurfaceTransaction_setFrameTimeline; # introduced=Tiramisu
     ASurfaceTransaction_setGeometry; # introduced=29
     ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index c2afc60..42f4406 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -619,6 +619,16 @@
     transaction->setFrameRate(surfaceControl, frameRate, compatibility, changeFrameRateStrategy);
 }
 
+void ASurfaceTransaction_clearFrameRate(ASurfaceTransaction* aSurfaceTransaction,
+                                        ASurfaceControl* aSurfaceControl) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    transaction->setFrameRate(surfaceControl, 0, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+                              ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+}
+
 void ASurfaceTransaction_setEnableBackPressure(ASurfaceTransaction* aSurfaceTransaction,
                                                ASurfaceControl* aSurfaceControl,
                                                bool enableBackpressure) {
diff --git a/native/graphics/jni/imagedecoder.cpp b/native/graphics/jni/imagedecoder.cpp
index 7fe2735..cd6ed23 100644
--- a/native/graphics/jni/imagedecoder.cpp
+++ b/native/graphics/jni/imagedecoder.cpp
@@ -381,7 +381,7 @@
 
     SkIRect cropIRect;
     cropIRect.setLTRB(crop.left, crop.top, crop.right, crop.bottom);
-    SkIRect* cropPtr = cropIRect.isEmpty() ? nullptr : &cropIRect;
+    SkIRect* cropPtr = cropIRect == SkIRect::MakeEmpty() ? nullptr : &cropIRect;
     return imageDecoder->setCropRect(cropPtr)
             ? ANDROID_IMAGE_DECODER_SUCCESS : ANDROID_IMAGE_DECODER_BAD_PARAMETER;
 }
diff --git a/opengl/java/android/opengl/GLLogWrapper.java b/opengl/java/android/opengl/GLLogWrapper.java
index bff7396..e645afa 100644
--- a/opengl/java/android/opengl/GLLogWrapper.java
+++ b/opengl/java/android/opengl/GLLogWrapper.java
@@ -2812,7 +2812,7 @@
     public void glDeleteBuffers(int n, int[] buffers, int offset) {
         begin("glDeleteBuffers");
         arg("n", n);
-        arg("buffers", buffers.toString());
+        arg("buffers", Arrays.toString(buffers));
         arg("offset", offset);
         end();
         mgl11.glDeleteBuffers(n, buffers, offset);
@@ -2831,7 +2831,7 @@
     public void glGenBuffers(int n, int[] buffers, int offset) {
         begin("glGenBuffers");
         arg("n", n);
-        arg("buffers", buffers.toString());
+        arg("buffers", Arrays.toString(buffers));
         arg("offset", offset);
         end();
         mgl11.glGenBuffers(n, buffers, offset);
@@ -2850,7 +2850,7 @@
     public void glGetBooleanv(int pname, boolean[] params, int offset) {
         begin("glGetBooleanv");
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetBooleanv(pname, params, offset);
@@ -2871,7 +2871,7 @@
         begin("glGetBufferParameteriv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetBufferParameteriv(target, pname, params, offset);
@@ -2891,7 +2891,7 @@
     public void glGetClipPlanef(int pname, float[] eqn, int offset) {
         begin("glGetClipPlanef");
         arg("pname", pname);
-        arg("eqn", eqn.toString());
+        arg("eqn", Arrays.toString(eqn));
         arg("offset", offset);
         end();
         mgl11.glGetClipPlanef(pname, eqn, offset);
@@ -2910,7 +2910,7 @@
     public void glGetClipPlanex(int pname, int[] eqn, int offset) {
         begin("glGetClipPlanex");
         arg("pname", pname);
-        arg("eqn", eqn.toString());
+        arg("eqn", Arrays.toString(eqn));
         arg("offset", offset);
         end();
         mgl11.glGetClipPlanex(pname, eqn, offset);
@@ -2928,7 +2928,7 @@
     public void glGetFixedv(int pname, int[] params, int offset) {
         begin("glGetFixedv");
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetFixedv(pname, params, offset);
@@ -2946,7 +2946,7 @@
     public void glGetFloatv(int pname, float[] params, int offset) {
         begin("glGetFloatv");
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetFloatv(pname, params, offset);
@@ -2965,7 +2965,7 @@
         begin("glGetLightfv");
         arg("light", light);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetLightfv(light, pname, params, offset);
@@ -2986,7 +2986,7 @@
         begin("glGetLightxv");
         arg("light", light);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetLightxv(light, pname, params, offset);
@@ -3008,7 +3008,7 @@
         begin("glGetMaterialfv");
         arg("face", face);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetMaterialfv(face, pname, params, offset);
@@ -3029,7 +3029,7 @@
         begin("glGetMaterialxv");
         arg("face", face);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetMaterialxv(face, pname, params, offset);
@@ -3050,7 +3050,7 @@
         begin("glGetTexEnviv");
         arg("env", env);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetTexEnviv(env, pname, params, offset);
@@ -3071,7 +3071,7 @@
         begin("glGetTexEnviv");
         arg("env", env);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetTexEnviv(env, pname, params, offset);
@@ -3092,7 +3092,7 @@
         begin("glGetTexParameterfv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetTexParameterfv(target, pname, params, offset);
@@ -3113,7 +3113,7 @@
         begin("glGetTexParameteriv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetTexEnviv(target, pname, params, offset);
@@ -3135,7 +3135,7 @@
         begin("glGetTexParameterxv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glGetTexParameterxv(target, pname, params, offset);
@@ -3191,7 +3191,7 @@
     public void glPointParameterfv(int pname, float[] params, int offset) {
         begin("glPointParameterfv");
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glPointParameterfv(pname, params, offset);
@@ -3219,7 +3219,7 @@
     public void glPointParameterxv(int pname, int[] params, int offset) {
         begin("glPointParameterxv");
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glPointParameterxv(pname, params, offset);
@@ -3259,7 +3259,7 @@
         begin("glTexEnviv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glTexEnviv(target, pname, params, offset);
@@ -3281,7 +3281,7 @@
         begin("glTexParameterfv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glTexParameterfv( target, pname, params, offset);
@@ -3313,7 +3313,7 @@
         begin("glTexParameterxv");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11.glTexParameterxv(target, pname, params, offset);
@@ -3356,7 +3356,7 @@
     public void glGetPointerv(int pname, Buffer[] params) {
         begin("glGetPointerv");
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         end();
         mgl11.glGetPointerv(pname, params);
         checkError();
@@ -3513,7 +3513,7 @@
     public void glDeleteFramebuffersOES(int n, int[] framebuffers, int offset) {
         begin("glDeleteFramebuffersOES");
         arg("n", n);
-        arg("framebuffers", framebuffers.toString());
+        arg("framebuffers", Arrays.toString(framebuffers));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glDeleteFramebuffersOES(n, framebuffers, offset);
@@ -3534,7 +3534,7 @@
     public void glDeleteRenderbuffersOES(int n, int[] renderbuffers, int offset) {
         begin("glDeleteRenderbuffersOES");
         arg("n", n);
-        arg("renderbuffers", renderbuffers.toString());
+        arg("renderbuffers", Arrays.toString(renderbuffers));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glDeleteRenderbuffersOES(n, renderbuffers, offset);
@@ -3591,7 +3591,7 @@
     public void glGenFramebuffersOES(int n, int[] framebuffers, int offset) {
         begin("glGenFramebuffersOES");
         arg("n", n);
-        arg("framebuffers", framebuffers.toString());
+        arg("framebuffers", Arrays.toString(framebuffers));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGenFramebuffersOES(n, framebuffers, offset);
@@ -3612,7 +3612,7 @@
     public void glGenRenderbuffersOES(int n, int[] renderbuffers, int offset) {
         begin("glGenRenderbuffersOES");
         arg("n", n);
-        arg("renderbuffers", renderbuffers.toString());
+        arg("renderbuffers", Arrays.toString(renderbuffers));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGenRenderbuffersOES(n, renderbuffers, offset);
@@ -3636,7 +3636,7 @@
         arg("target", target);
         arg("attachment", attachment);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGetFramebufferAttachmentParameterivOES(target, attachment, pname, params, offset);
@@ -3662,7 +3662,7 @@
         begin("glGetRenderbufferParameterivOES");
         arg("target", target);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGetRenderbufferParameterivOES(target, pname, params, offset);
@@ -3686,7 +3686,7 @@
         begin("glGetTexGenfv");
         arg("coord", coord);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGetTexGenfv(coord, pname, params, offset);
@@ -3709,7 +3709,7 @@
         begin("glGetTexGeniv");
         arg("coord", coord);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGetTexGeniv(coord, pname, params, offset);
@@ -3732,7 +3732,7 @@
         begin("glGetTexGenxv");
         arg("coord", coord);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glGetTexGenxv(coord, pname, params, offset);
@@ -3799,7 +3799,7 @@
         begin("glTexGenfv");
         arg("coord", coord);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glTexGenfv(coord, pname, params, offset);
@@ -3833,7 +3833,7 @@
         begin("glTexGeniv");
         arg("coord", coord);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glTexGeniv(coord, pname, params, offset);
@@ -3867,7 +3867,7 @@
         begin("glTexGenxv");
         arg("coord", coord);
         arg("pname", pname);
-        arg("params", params.toString());
+        arg("params", Arrays.toString(params));
         arg("offset", offset);
         end();
         mgl11ExtensionPack.glTexGenxv(coord, pname, params, offset);
diff --git a/packages/BackupRestoreConfirmation/res/values-or/strings.xml b/packages/BackupRestoreConfirmation/res/values-or/strings.xml
index 1c54569..cb610921 100644
--- a/packages/BackupRestoreConfirmation/res/values-or/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-or/strings.xml
@@ -20,7 +20,7 @@
     <string name="restore_confirm_title" msgid="5469365809567486602">"ସମ୍ପୂର୍ଣ୍ଣ ରିଷ୍ଟୋର୍‌"</string>
     <string name="backup_confirm_text" msgid="1878021282758896593">"ଏକ ସଂଯୁକ୍ତ ଡେସ୍କଟପ୍‌ କମ୍ପ୍ୟୁଟର୍‌କୁ ସମସ୍ତ ଡାଟାର ସମ୍ପୂର୍ଣ୍ଣ ବ୍ୟାକଅପ୍‌ କରିବାକୁ ଅନୁରୋଧ କରାଯାଇଛି। ଆପଣ ଏହିପରି କରିବାକୁ ଚାହିଁବେ?\n\nଯଦି ଆପଣ ନିଜେ ବ୍ୟାକଅପ୍‌ର ଅନୁରୋଧ କରିନାହାନ୍ତି, ତେବେ ଏହି କାମକୁ ଆଗକୁ ବଢ଼ିବାକୁ ଦିଅନ୍ତୁ ନାହିଁ।"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"ମୋ ଡାଟାର ବ୍ୟାକଅପ୍‌ ନିଆଯାଉ"</string>
-    <string name="deny_backup_button_label" msgid="6009119115581097708">"ବ୍ୟାକଅପ୍‌ ନିଆନଯାଉ"</string>
+    <string name="deny_backup_button_label" msgid="6009119115581097708">"ବେକଅପ ନିଅନ୍ତୁ ନାହିଁ"</string>
     <string name="restore_confirm_text" msgid="7499866728030461776">"ଏକ ସଂଯୁକ୍ତ ଡେସ୍କଟପ୍‌ କମ୍ପ୍ୟୁଟର୍‌ରୁ ସମସ୍ତ ଡାଟାର ସମ୍ପୂର୍ଣ୍ଣ ରିଷ୍ଟୋର୍‌ ଅନୁରୋଧ କରାଯାଇଛି। ଆପଣ ଏହାକୁ ଅନୁମତି ଦେବାକୁ ଚାହିଁବେ କି?\n\nଯଦି ଆପଣ ନିଜେ ରିଷ୍ଟୋର୍‌ ଅନୁରୋଧ କରିନାହାନ୍ତି, ତେବେ ଏହା କାର୍ଯ୍ୟକୁ ଆଗକୁ ବଢ଼ିବାକୁ ଦିଅନ୍ତୁ ନାହିଁ। ଏହା ବର୍ତ୍ତମାନ ଡିଭାଇସ୍‍ରେ ଥିବା ଯେକୌଣସି ଡାଟାକୁ ବଦଳାଇଦେବ!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"ମୋ ଡାଟାକୁ ରିଷ୍ଟୋର୍‌ କରାଯାଉ"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"ରିଷ୍ଟୋର୍‍ କରନ୍ତୁ ନାହିଁ।"</string>
diff --git a/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml b/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
index a1e6167..1f6be83 100644
--- a/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-pt-rPT/strings.xml
@@ -20,7 +20,7 @@
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restauro completo"</string>
     <string name="backup_confirm_text" msgid="1878021282758896593">"Foi solicitada uma cópia de segurança completa de todos os dados para um computador. Permitir esta operação?\n\nCaso não tenha solicitado a cópia de segurança, não permita que a operação prossiga."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Fazer cópia de seg. dos dados"</string>
-    <string name="deny_backup_button_label" msgid="6009119115581097708">"Não efetuar cópia de seg."</string>
+    <string name="deny_backup_button_label" msgid="6009119115581097708">"Não fazer cópia de seg."</string>
     <string name="restore_confirm_text" msgid="7499866728030461776">"Foi solicitado um restauro completo de todos os dados a partir de um computador. Permitir esta operação?\n\nCaso não tenha solicitado o restauro, não permita que a operação prossiga. Isto substituirá os dados existentes no equipamento!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restaurar os meus dados"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Não restaurar"</string>
diff --git a/packages/CompanionDeviceManager/res/drawable-night/ic_info.xml b/packages/CompanionDeviceManager/res/drawable-night/ic_info.xml
index 5689e34..a984938 100644
--- a/packages/CompanionDeviceManager/res/drawable-night/ic_info.xml
+++ b/packages/CompanionDeviceManager/res/drawable-night/ic_info.xml
@@ -19,7 +19,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
-        android:tint="@android:color/system_accent1_200">
+        android:tint="@android:color/system_neutral1_200">
     <path android:fillColor="@android:color/white"
           android:pathData="M11,17H13V11H11ZM12,9Q12.425,9 12.713,8.712Q13,8.425 13,8Q13,7.575 12.713,7.287Q12.425,7 12,7Q11.575,7 11.288,7.287Q11,7.575 11,8Q11,8.425 11.288,8.712Q11.575,9 12,9ZM12,22Q9.925,22 8.1,21.212Q6.275,20.425 4.925,19.075Q3.575,17.725 2.788,15.9Q2,14.075 2,12Q2,9.925 2.788,8.1Q3.575,6.275 4.925,4.925Q6.275,3.575 8.1,2.787Q9.925,2 12,2Q14.075,2 15.9,2.787Q17.725,3.575 19.075,4.925Q20.425,6.275 21.212,8.1Q22,9.925 22,12Q22,14.075 21.212,15.9Q20.425,17.725 19.075,19.075Q17.725,20.425 15.9,21.212Q14.075,22 12,22ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12ZM12,20Q15.325,20 17.663,17.663Q20,15.325 20,12Q20,8.675 17.663,6.337Q15.325,4 12,4Q8.675,4 6.338,6.337Q4,8.675 4,12Q4,15.325 6.338,17.663Q8.675,20 12,20Z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/drawable/ic_info.xml b/packages/CompanionDeviceManager/res/drawable/ic_info.xml
index d9f6a27..229960c 100644
--- a/packages/CompanionDeviceManager/res/drawable/ic_info.xml
+++ b/packages/CompanionDeviceManager/res/drawable/ic_info.xml
@@ -20,7 +20,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
-        android:tint="@android:color/system_accent1_600">
+        android:tint="@android:color/system_neutral1_700">
     <path android:fillColor="@android:color/white"
           android:pathData="M11,17H13V11H11ZM12,9Q12.425,9 12.713,8.712Q13,8.425 13,8Q13,7.575 12.713,7.287Q12.425,7 12,7Q11.575,7 11.288,7.287Q11,7.575 11,8Q11,8.425 11.288,8.712Q11.575,9 12,9ZM12,22Q9.925,22 8.1,21.212Q6.275,20.425 4.925,19.075Q3.575,17.725 2.788,15.9Q2,14.075 2,12Q2,9.925 2.788,8.1Q3.575,6.275 4.925,4.925Q6.275,3.575 8.1,2.787Q9.925,2 12,2Q14.075,2 15.9,2.787Q17.725,3.575 19.075,4.925Q20.425,6.275 21.212,8.1Q22,9.925 22,12Q22,14.075 21.212,15.9Q20.425,17.725 19.075,19.075Q17.725,20.425 15.9,21.212Q14.075,22 12,22ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12ZM12,20Q15.325,20 17.663,17.663Q20,15.325 20,12Q20,8.675 17.663,6.337Q15.325,4 12,4Q8.675,4 6.338,6.337Q4,8.675 4,12Q4,15.325 6.338,17.663Q8.675,20 12,20Z"/>
 </vector>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
index d0d46f7..1f922b9 100644
--- a/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
+++ b/packages/CompanionDeviceManager/res/layout/helper_confirmation.xml
@@ -35,7 +35,7 @@
             <ImageView
                 android:id="@+id/app_icon"
                 android:layout_width="match_parent"
-                android:layout_height="48dp"
+                android:layout_height="32dp"
                 android:gravity="center"
                 android:layout_marginTop="12dp"
                 android:layout_marginBottom="12dp"/>
diff --git a/packages/CompanionDeviceManager/res/layout/vendor_header.xml b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
index 14e7431..16a87e5 100644
--- a/packages/CompanionDeviceManager/res/layout/vendor_header.xml
+++ b/packages/CompanionDeviceManager/res/layout/vendor_header.xml
@@ -22,7 +22,7 @@
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:layout_gravity="center"
-    android:paddingTop="24dp"
+    android:paddingTop="12dp"
     android:paddingBottom="4dp"
     android:paddingStart="24dp"
     android:paddingEnd="24dp"
@@ -32,24 +32,26 @@
         android:id="@+id/vendor_header_image"
         android:layout_width="48dp"
         android:layout_height="48dp"
+        android:padding="12dp"
         android:contentDescription="@string/vendor_icon_description" />
 
     <TextView
         android:id="@+id/vendor_header_name"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginStart="12dp"
         android:layout_marginTop="12dp"
-        android:textSize="16sp"
+        android:textSize="14sp"
         android:layout_toEndOf="@+id/vendor_header_image"
         android:textColor="?android:attr/textColorSecondary"/>
 
     <ImageButton
         android:id="@+id/vendor_header_button"
-        android:background="@drawable/ic_info"
+        android:src="@drawable/ic_info"
         android:layout_width="48dp"
         android:layout_height="48dp"
+        android:padding="12dp"
         android:contentDescription="@string/vendor_header_button_description"
-        android:layout_alignParentEnd="true" />
+        android:layout_alignParentEnd="true"
+        android:background="@android:color/transparent" />
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index 867d70f..2d78b26 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -34,7 +34,7 @@
     <string name="permission_notification_summary" msgid="884075314530071011">"इससे सभी सूचनाएं देखी जा सकती हैं. इसमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल होती है"</string>
     <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
     <string name="permission_storage_summary" msgid="3918240895519506417"></string>
-    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवाएं"</string>
+    <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
     <string name="summary_generic" msgid="2346762210105903720"></string>
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-night/themes.xml b/packages/CompanionDeviceManager/res/values-night/themes.xml
index 6eb16e7..55e91b6 100644
--- a/packages/CompanionDeviceManager/res/values-night/themes.xml
+++ b/packages/CompanionDeviceManager/res/values-night/themes.xml
@@ -18,8 +18,8 @@
 
     <style name="ChooserActivity"
            parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
-        <item name="*android:windowFixedHeightMajor">100%</item>
-        <item name="*android:windowFixedHeightMinor">100%</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowNoTitle">true</item>
         <item name="android:windowBackground">@android:color/transparent</item>
     </style>
 
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/res/values/styles.xml b/packages/CompanionDeviceManager/res/values/styles.xml
index 2000d96..428f2dc 100644
--- a/packages/CompanionDeviceManager/res/values/styles.xml
+++ b/packages/CompanionDeviceManager/res/values/styles.xml
@@ -49,6 +49,7 @@
     <style name="DescriptionSummary">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
+        <item name="android:gravity">center</item>
         <item name="android:layout_marginTop">18dp</item>
         <item name="android:layout_marginLeft">18dp</item>
         <item name="android:layout_marginRight">18dp</item>
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-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index ff9f652..1698150 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -5,7 +5,7 @@
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"የAndroid የቁልፍ ሰሌዳ"</string>
     <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"እንግሊዝኛ (ዩኬ)"</string>
     <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"እንግሊዘኛ (ዩ.ኤስ.)"</string>
-    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"እንግሊዘኛ (ዩ. ኤስ.)፣ አለም አቀፍ ቅጥ"</string>
+    <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"እንግሊዘኛ (ዩ. ኤስ.)፣ ዓለም አቀፍ ቅጥ"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"እንግሊዘኛ (ዩ. ኤስ.)፣ የኮልማርክ ቅጥ"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"እንግሊዘኛ (ዩ. ኤስ.)፣ የድቮራክ ቅጥ"</string>
     <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"እንግሊዝኛ (አሜሪካ)፣ የሥራሰው ቅጥ"</string>
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/PackageInstaller/res/values-it/strings.xml b/packages/PackageInstaller/res/values-it/strings.xml
index 74f7d908..3fe7ba4 100644
--- a/packages/PackageInstaller/res/values-it/strings.xml
+++ b/packages/PackageInstaller/res/values-it/strings.xml
@@ -37,7 +37,7 @@
     <string name="install_failed_msg" product="tv" msgid="1920009940048975221">"Impossibile installare <xliff:g id="APP_NAME">%1$s</xliff:g> sulla TV."</string>
     <string name="install_failed_msg" product="default" msgid="6484461562647915707">"Impossibile installare <xliff:g id="APP_NAME">%1$s</xliff:g> sul telefono."</string>
     <string name="launch" msgid="3952550563999890101">"Apri"</string>
-    <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"L\'amministratore non consente l\'installazione di app ottenute da fonti sconosciute"</string>
+    <string name="unknown_apps_admin_dlg_text" msgid="4456572224020176095">"L\'amministratore non consente l\'installazione di app ottenute da origini sconosciute"</string>
     <string name="unknown_apps_user_restriction_dlg_text" msgid="151020786933988344">"Questo utente non può installare app sconosciute"</string>
     <string name="install_apps_user_restriction_dlg_text" msgid="2154119597001074022">"L\'utente non è autorizzato a installare app"</string>
     <string name="ok" msgid="7871959885003339302">"OK"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/DeviceUtils.java b/packages/PackageInstaller/src/com/android/packageinstaller/DeviceUtils.java
index b54cad6..40a9390 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/DeviceUtils.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/DeviceUtils.java
@@ -18,12 +18,10 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 
 public class DeviceUtils {
     public static boolean isTelevision(Context context) {
-        int uiMode = context.getResources().getConfiguration().uiMode;
-        return (uiMode & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION;
+        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
     }
 
     public static boolean isWear(final Context context) {
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/build.gradle b/packages/SettingsLib/Spa/build.gradle
index d380136..5dc2aa0 100644
--- a/packages/SettingsLib/Spa/build.gradle
+++ b/packages/SettingsLib/Spa/build.gradle
@@ -22,7 +22,7 @@
     }
 }
 plugins {
-    id 'com.android.application' version '7.3.0-beta04' apply false
-    id 'com.android.library' version '7.3.0-beta04' apply false
+    id 'com.android.application' version '7.3.0-rc01' apply false
+    id 'com.android.library' version '7.3.0-rc01' apply false
     id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
 }
diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
index 2229986..e5bf8ca 100644
--- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
+++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
@@ -29,6 +29,10 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-    </application>
 
+        <activity
+            android:name=".GalleryDebugActivity"
+            android:exported="true">
+        </activity>
+    </application>
 </manifest>
diff --git a/packages/SettingsLib/Spa/gallery/res/drawable/accessibility_captioning_banner.xml b/packages/SettingsLib/Spa/gallery/res/drawable/accessibility_captioning_banner.xml
new file mode 100644
index 0000000..6597ffb
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/res/drawable/accessibility_captioning_banner.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="412dp"
+    android:height="300dp"
+    android:viewportWidth="412"
+    android:viewportHeight="300">
+  <path
+      android:pathData="M383.9,300H28.1C12.6,300 0,287.4 0,271.9V28.1C0,12.6 12.6,0 28.1,0h355.8C399.4,0 412,12.6 412,28.1v243.8C412,287.4 399.4,300 383.9,300z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M79.2,179.6h53.6v8.5h-53.6z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M142.5,179.6h30.4v8.5h-30.4z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M79.2,195.5h79.2v8.5h-79.2z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M168.1,195.5h34.1v8.5h-34.1z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M211.9,195.5h34.1v8.5h-34.1z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M182.7,179.6h73.1v8.5h-73.1z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M265.5,179.6h26.8v8.5h-26.8z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M302.1,179.6h26.8v8.5h-26.8z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M142.7,67.9h-11.5c-1.6,0 -2.9,1.3 -2.9,2.9H67.8c-7.9,0 -14.4,6.5 -14.4,14.4v132.4c0,7.9 6.5,14.4 14.4,14.4h276.4c7.9,0 14.4,-6.5 14.4,-14.4V85.2c0,-7.9 -6.5,-14.4 -14.4,-14.4H203.1c0,-1.6 -1.3,-2.9 -2.9,-2.9h-28.8c-1.6,0 -2.9,1.3 -2.9,2.9h-23C145.5,69.2 144.3,67.9 142.7,67.9zM344.2,73.7c6.4,0 11.5,5.2 11.5,11.5v132.4c0,6.3 -5.2,11.5 -11.5,11.5H67.8c-6.4,0 -11.5,-5.2 -11.5,-11.5V85.2c0,-6.3 5.2,-11.5 11.5,-11.5H344.2z"
+      android:fillColor="#DADCE0"/>
+</vector>
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/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt
similarity index 74%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt
index 88e227b..317346d 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GalleryDebugActivity.kt
@@ -14,10 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package com.android.settingslib.spa.gallery
 
-import javax.inject.Qualifier
+import com.android.settingslib.spa.framework.DebugActivity
 
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+class GalleryDebugActivity : DebugActivity(SpaEnvironment.EntryRepository, MainActivity::class.java)
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt
index 6e6da52..a063847 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/MainActivity.kt
@@ -18,4 +18,4 @@
 
 import com.android.settingslib.spa.framework.BrowseActivity
 
-class MainActivity : BrowseActivity(galleryPageProviders)
+class MainActivity : BrowseActivity(SpaEnvironment.PageProviderRepository)
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 e300624..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
@@ -16,26 +16,49 @@
 
 package com.android.settingslib.spa.gallery
 
+import com.android.settingslib.spa.framework.common.SettingsEntryRepository
+import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
 import com.android.settingslib.spa.gallery.home.HomePageProvider
 import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
 import com.android.settingslib.spa.gallery.page.FooterPageProvider
-import com.android.settingslib.spa.gallery.page.PreferencePageProvider
+import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
 import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
 import com.android.settingslib.spa.gallery.page.SliderPageProvider
-import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider
+import com.android.settingslib.spa.gallery.preference.MainSwitchPreferencePageProvider
+import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider
+import com.android.settingslib.spa.gallery.preference.PreferencePageProvider
+import com.android.settingslib.spa.gallery.preference.SwitchPreferencePageProvider
+import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider
+import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider
 
-val galleryPageProviders = SettingsPageProviderRepository(
-    allPagesList = listOf(
-        HomePageProvider,
-        PreferencePageProvider,
-        SwitchPreferencePageProvider,
-        ArgumentPageProvider,
-        SliderPageProvider,
-        SettingsPagerPageProvider,
-        FooterPageProvider,
-    ),
-    rootPages = listOf(HomePageProvider.name)
-)
+object SpaEnvironment {
+    val PageProviderRepository: SettingsPageProviderRepository by
+    lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
+        SettingsPageProviderRepository(
+            allPageProviders = listOf(
+                HomePageProvider,
+                PreferenceMainPageProvider,
+                PreferencePageProvider,
+                SwitchPreferencePageProvider,
+                MainSwitchPreferencePageProvider,
+                TwoTargetSwitchPreferencePageProvider,
+                ArgumentPageProvider,
+                SliderPageProvider,
+                SpinnerPageProvider,
+                SettingsPagerPageProvider,
+                FooterPageProvider,
+                IllustrationPageProvider,
+            ),
+            rootPages = listOf(
+                SettingsPage.create(HomePageProvider.name)
+            )
+        )
+    }
 
-// TODO: add other environment setup here.
+    val EntryRepository: SettingsEntryRepository by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
+        SettingsEntryRepository(PageProviderRepository)
+    }
+
+    // TODO: add other environment setup here.
+}
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 a85ee2a..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
@@ -20,36 +20,48 @@
 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.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.PreferencePageProvider
+import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
 import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
 import com.android.settingslib.spa.gallery.page.SliderPageProvider
-import com.android.settingslib.spa.gallery.page.SwitchPreferencePageProvider
+import com.android.settingslib.spa.gallery.preference.PreferenceMainPageProvider
+import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider
 import com.android.settingslib.spa.widget.scaffold.HomeScaffold
 
 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)) {
-        PreferencePageProvider.EntryItem()
-        SwitchPreferencePageProvider.EntryItem()
-        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = 0)
-
-        SliderPageProvider.EntryItem()
-        SettingsPagerPageProvider.EntryItem()
-        FooterPageProvider.EntryItem()
+        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()
+                }
+            }
+        }
     }
 }
 
@@ -57,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 bd366c3..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
@@ -19,63 +19,77 @@
 import android.os.Bundle
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.tooling.preview.Preview
-import androidx.navigation.NavType
-import androidx.navigation.navArgument
+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
 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.RegularScaffold
 
-private const val TITLE = "Sample page with arguments"
-private const val STRING_PARAM_NAME = "stringParam"
-private const val INT_PARAM_NAME = "intParam"
-
 object ArgumentPageProvider : SettingsPageProvider {
-    override val name = "Argument"
+    override val name = ArgumentPageModel.name
 
-    override val arguments = listOf(
-        navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
-        navArgument(INT_PARAM_NAME) { type = NavType.IntType },
-    )
+    override val parameter = ArgumentPageModel.parameter
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        if (!ArgumentPageModel.isValidArgument(arguments)) return emptyList()
+
+        val owner = SettingsPage.create(name, parameter, arguments)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create("string_param", owner)
+                // Set attributes
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    // Set ui rendering
+                    Preference(ArgumentPageModel.create(it).genStringParamPreferenceModel())
+                }.build()
+        )
+
+        entryList.add(
+            SettingsEntryBuilder.create("int_param", owner)
+                // Set attributes
+                .setIsAllowSearch(true)
+                .setUiLayoutFn {
+                    // Set ui rendering
+                    Preference(ArgumentPageModel.create(it).genIntParamPreferenceModel())
+                }.build()
+        )
+
+        entryList.add(buildInjectEntry("foo")!!.setLink(fromPage = owner).build())
+        entryList.add(buildInjectEntry("bar")!!.setLink(fromPage = owner).build())
+
+        return entryList
+    }
+
+    fun buildInjectEntry(stringParam: String): SettingsEntryBuilder? {
+        val arguments = ArgumentPageModel.buildArgument(stringParam)
+        if (!ArgumentPageModel.isValidArgument(arguments)) return null
+
+        return SettingsEntryBuilder.createInject(
+            entryName = "${name}_$stringParam",
+            owner = SettingsPage.create(name, parameter, arguments)
+        )
+            // Set attributes
+            .setIsAllowSearch(false)
+            .setUiLayoutFn {
+                // Set ui rendering
+                Preference(ArgumentPageModel.create(it).genInjectPreferenceModel())
+            }
+    }
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        ArgumentPage(
-            stringParam = arguments!!.getString(STRING_PARAM_NAME, "default"),
-            intParam = arguments.getInt(INT_PARAM_NAME),
-        )
-    }
-
-    @Composable
-    fun EntryItem(stringParam: String, intParam: Int) {
-        Preference(object : PreferenceModel {
-            override val title = TITLE
-            override val summary =
-                "$STRING_PARAM_NAME=$stringParam, $INT_PARAM_NAME=$intParam".toState()
-            override val onClick = navigator("$name/$stringParam/$intParam")
-        })
-    }
-}
-
-@Composable
-fun ArgumentPage(stringParam: String, intParam: Int) {
-    RegularScaffold(title = TITLE) {
-        Preference(object : PreferenceModel {
-            override val title = "String param value"
-            override val summary = stringParam.toState()
-        })
-
-        Preference(object : PreferenceModel {
-            override val title = "Int param value"
-            override val summary = intParam.toString().toState()
-        })
-
-        ArgumentPageProvider.EntryItem(stringParam = "foo", intParam = intParam + 1)
-
-        ArgumentPageProvider.EntryItem(stringParam = "bar", intParam = intParam + 1)
+        RegularScaffold(title = ArgumentPageModel.create(arguments).genPageTitle()) {
+            for (entry in buildEntry(arguments)) {
+                if (entry.name.startsWith(name)) {
+                    entry.UiLayout(ArgumentPageModel.buildNextArgument(arguments))
+                } else {
+                    entry.UiLayout()
+                }
+            }
+        }
     }
 }
 
@@ -83,6 +97,8 @@
 @Composable
 private fun ArgumentPagePreview() {
     SettingsTheme {
-        ArgumentPage(stringParam = "foo", intParam = 0)
+        ArgumentPageProvider.Page(
+            ArgumentPageModel.buildArgument(stringParam = "foo", intParam = 0)
+        )
     }
 }
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
new file mode 100644
index 0000000..6e86fd7
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPageModel.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.gallery.page
+
+import android.os.Bundle
+import android.util.Log
+import androidx.compose.runtime.Composable
+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
+import com.android.settingslib.spa.framework.util.getIntArg
+import com.android.settingslib.spa.framework.util.getStringArg
+import com.android.settingslib.spa.framework.util.navLink
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+
+private const val TITLE = "Sample page with arguments"
+private const val STRING_PARAM_NAME = "stringParam"
+private const val INT_PARAM_NAME = "intParam"
+
+class ArgumentPageModel : PageModel() {
+
+    companion object {
+        const val name = "Argument"
+        val parameter = listOf(
+            navArgument(STRING_PARAM_NAME) { type = NavType.StringType },
+            navArgument(INT_PARAM_NAME) { type = NavType.IntType },
+        )
+
+        fun buildArgument(stringParam: String? = null, intParam: Int? = null): Bundle {
+            val args = Bundle()
+            if (stringParam != null) args.putString(STRING_PARAM_NAME, stringParam)
+            if (intParam != null) args.putInt(INT_PARAM_NAME, intParam)
+            return args
+        }
+
+        fun buildNextArgument(arguments: Bundle? = null): Bundle {
+            val intParam = parameter.getIntArg(INT_PARAM_NAME, arguments)
+            val nextIntParam = if (intParam != null) intParam + 1 else null
+            return buildArgument(intParam = nextIntParam)
+        }
+
+        fun isValidArgument(arguments: Bundle?): Boolean {
+            val stringParam = parameter.getStringArg(STRING_PARAM_NAME, arguments)
+            return (stringParam != null && listOf("foo", "bar").contains(stringParam))
+        }
+
+        @Composable
+        fun create(arguments: Bundle?): ArgumentPageModel {
+            val pageModel: ArgumentPageModel = viewModel(key = arguments.toString())
+            pageModel.initOnce(arguments)
+            return pageModel
+        }
+    }
+
+    private val title = TITLE
+    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
+    fun genPageTitle(): String {
+        return title
+    }
+
+    @Composable
+    fun genStringParamPreferenceModel(): PreferenceModel {
+        return object : PreferenceModel {
+            override val title = "String param value"
+            override val summary = stateOf(stringParam!!)
+        }
+    }
+
+    @Composable
+    fun genIntParamPreferenceModel(): PreferenceModel {
+        return object : PreferenceModel {
+            override val title = "Int param value"
+            override val summary = stateOf(intParam!!.toString())
+        }
+    }
+
+    @Composable
+    fun genInjectPreferenceModel(): PreferenceModel {
+        val summaryArray = listOf(
+            "$STRING_PARAM_NAME=" + stringParam!!,
+            "$INT_PARAM_NAME=" + intParam!!
+        )
+        return object : PreferenceModel {
+            override val title = genPageTitle()
+            override val summary = stateOf(summaryArray.joinToString(", "))
+            override val onClick = navigator(name + parameter.navLink(arguments))
+        }
+    }
+}
+
+private fun logMsg(message: String) {
+    Log.d("ArgumentPageModel", message)
+}
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
new file mode 100644
index 0000000..a64d4a5
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.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.spa.gallery.page
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+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
+import com.android.settingslib.spa.gallery.R
+import com.android.settingslib.spa.widget.Illustration
+import com.android.settingslib.spa.widget.IllustrationModel
+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?) {
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun IllustrationPagePreview() {
+    SettingsTheme {
+        IllustrationPageProvider.Page(null)
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt
deleted file mode 100644
index 90dacdb..0000000
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/PreferencePage.kt
+++ /dev/null
@@ -1,118 +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.settingslib.spa.gallery.page
-
-import android.os.Bundle
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.outlined.DisabledByDefault
-import androidx.compose.material.icons.outlined.TouchApp
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.produceState
-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.SettingsPageProvider
-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.RegularScaffold
-import com.android.settingslib.spa.widget.ui.SettingsIcon
-import kotlinx.coroutines.delay
-
-private const val TITLE = "Sample Preference"
-
-object PreferencePageProvider : SettingsPageProvider {
-    override val name = "Preference"
-
-    @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"
-            }
-        })
-
-        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)
-            }
-        })
-    }
-}
-
-@Preview(showBackground = true)
-@Composable
-private fun PreferencePagePreview() {
-    SettingsTheme {
-        PreferencePage()
-    }
-}
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 3146351..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,73 +27,105 @@
 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
+import com.android.settingslib.spa.widget.SettingsSlider
+import com.android.settingslib.spa.widget.SettingsSliderModel
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
-import com.android.settingslib.spa.widget.ui.SettingsSlider
-import com.android.settingslib.spa.widget.ui.SettingsSliderModel
 
 private const val TITLE = "Sample Slider"
 
 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
new file mode 100644
index 0000000..a8e4938
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.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.settingslib.spa.gallery.preference
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+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
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.preference.MainSwitchPreference
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+
+private const val TITLE = "Sample MainSwitchPreference"
+
+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?) {
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
+    }
+}
+
+@Composable
+private fun SampleMainSwitchPreference() {
+    val checked = rememberSaveable { mutableStateOf(false) }
+    MainSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "MainSwitchPreference"
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
+
+@Composable
+private fun SampleNotChangeableMainSwitchPreference() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    MainSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "Not changeable"
+            override val changeable = stateOf(false)
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun MainSwitchPreferencePagePreview() {
+    SettingsTheme {
+        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
new file mode 100644
index 0000000..0f99c57
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.gallery.preference
+
+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
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+
+private const val TITLE = "Category: Preference"
+
+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?) {
+        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
new file mode 100644
index 0000000..cbd028d
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.gallery.preference
+
+import android.os.Bundle
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.DisabledByDefault
+import androidx.compose.material.icons.outlined.TouchApp
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.produceState
+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
+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.RegularScaffold
+import com.android.settingslib.spa.widget.ui.SettingsIcon
+import kotlinx.coroutines.delay
+
+private const val TITLE = "Sample Preference"
+
+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?) {
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun PreferencePagePreview() {
+    SettingsTheme {
+        PreferencePageProvider.Page(null)
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
similarity index 64%
rename from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt
rename to packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
index 6d5d4483..46b44ca 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.spa.gallery.page
+package com.android.settingslib.spa.gallery.preference
 
 import android.os.Bundle
 import androidx.compose.runtime.Composable
@@ -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
new file mode 100644
index 0000000..b991f59
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
@@ -0,0 +1,163 @@
+/*
+ * 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.gallery.preference
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.produceState
+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
+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.preference.SwitchPreferenceModel
+import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import kotlinx.coroutines.delay
+
+private const val TITLE = "Sample TwoTargetSwitchPreference"
+
+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?) {
+        RegularScaffold(title = TITLE) {
+            for (entry in buildEntry(arguments)) {
+                entry.UiLayout()
+            }
+        }
+    }
+}
+
+@Composable
+private fun SampleTwoTargetSwitchPreference() {
+    val checked = rememberSaveable { mutableStateOf(false) }
+    TwoTargetSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "TwoTargetSwitchPreference"
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    }) {}
+}
+
+@Composable
+private fun SampleTwoTargetSwitchPreferenceWithSummary() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    TwoTargetSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "TwoTargetSwitchPreference"
+            override val summary = stateOf("With summary")
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    }) {}
+}
+
+@Composable
+private fun SampleTwoTargetSwitchPreferenceWithAsyncSummary() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    val summary = produceState(initialValue = " ") {
+        delay(1000L)
+        value = "Async summary"
+    }
+    TwoTargetSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "TwoTargetSwitchPreference"
+            override val summary = summary
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    }) {}
+}
+
+@Composable
+private fun SampleNotChangeableTwoTargetSwitchPreference() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    TwoTargetSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "TwoTargetSwitchPreference"
+            override val summary = stateOf("Not changeable")
+            override val changeable = stateOf(false)
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    }) {}
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun TwoTargetSwitchPreferencePagePreview() {
+    SettingsTheme {
+        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
new file mode 100644
index 0000000..03b72d3
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.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.settingslib.spa.gallery.ui
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.mutableStateOf
+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
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import com.android.settingslib.spa.widget.ui.Spinner
+
+private const val TITLE = "Sample Spinner"
+
+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?) {
+        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() }
+                }
+            })
+        }
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun SpinnerPagePreview() {
+    SettingsTheme {
+        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 ad69da31..104966d 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle
+++ b/packages/SettingsLib/Spa/spa/build.gradle
@@ -66,4 +66,5 @@
     api 'androidx.navigation:navigation-compose:2.5.0'
     api 'com.google.android.material:material:1.6.1'
     debugApi "androidx.compose.ui:ui-tooling:$jetpack_compose_version"
+    implementation 'com.airbnb.android:lottie-compose:5.2.0'
 }
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 6a7b17a..ae15da6 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
@@ -21,14 +21,18 @@
 import androidx.activity.compose.setContent
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
+import androidx.navigation.NavGraph.Companion.findStartDestination
 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.SettingsPageProvider
+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
+import com.android.settingslib.spa.framework.util.navRoute
 
 open class BrowseActivity(
     private val sppRepository: SettingsPageProviderRepository,
@@ -46,28 +50,41 @@
 
     @Composable
     private fun MainContent() {
-        val startDestination =
-            intent?.getStringExtra(KEY_START_DESTINATION) ?: sppRepository.getDefaultStartPageName()
+        val destination =
+            intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPageName()
 
         val navController = rememberNavController()
         CompositionLocalProvider(navController.localNavController()) {
-            NavHost(navController, startDestination) {
+            NavHost(navController, ROOT_PAGE_NAME) {
+                composable(ROOT_PAGE_NAME) {}
                 for (page in sppRepository.getAllProviders()) {
                     composable(
-                        route = page.route,
-                        arguments = page.arguments,
+                        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.isNotEmpty()) {
+                LaunchedEffect(Unit) {
+                    navController.navigate(destination) {
+                        popUpTo(navController.graph.findStartDestination().id) {
+                            inclusive = true
+                        }
+                    }
+                }
+            }
         }
     }
 
-    private val SettingsPageProvider.route: String
-        get() = name + arguments.joinToString("") { argument -> "/{${argument.name}}" }
-
     companion object {
-        const val KEY_START_DESTINATION = "spa:SpaActivity:startDestination"
+        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..bd5aaa7
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/DebugActivity.kt
@@ -0,0 +1,210 @@
+/*
+ * 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.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.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<*>,
+) : ComponentActivity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        setTheme(R.style.Theme_SpaLib_DayNight)
+        super.onCreate(savedInstanceState)
+
+        val packageName = browseActivityClass.packageName
+        val className = browseActivityClass.toString().removePrefix("class $packageName")
+        for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
+            if (pageWithEntry.page.hasRuntimeParam()) continue
+            val route = pageWithEntry.page.buildRoute()
+            Log.d(
+                "DEBUG ACTIVITY",
+                "adb shell am start -n $packageName/$className -e $KEY_DESTINATION $route"
+            )
+        }
+
+        setContent {
+            SettingsTheme {
+                MainContent()
+            }
+        }
+    }
+
+    @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.displayName} (${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.displayName}") {
+            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?.displayName} -> ${entry.toPage?.displayName}".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/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/PageModel.kt
similarity index 60%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/PageModel.kt
index e62a63a..ee12f02 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/PageModel.kt
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.desktopmode;
+package com.android.settingslib.spa.framework.common
 
-import android.os.SystemProperties;
+import android.os.Bundle
+import androidx.lifecycle.ViewModel
 
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
+open class PageModel : ViewModel() {
+    var initialized = false
 
-    /**
-     * Flag to indicate whether desktop mode is available on the device
-     */
-    public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+    fun initOnce(arguments: Bundle?) {
+        // Initialize only once
+        if (initialized) return
+        initialized = true
+        initialize(arguments)
+    }
+
+    open fun initialize(arguments: Bundle?) {}
 }
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
new file mode 100644
index 0000000..b0a1cbe
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -0,0 +1,323 @@
+/*
+ * 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.common
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.navigation.NamedNavArgument
+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.
+ */
+data class SearchData(val keyword: String = "")
+
+/**
+ * Defines data of one Settings entry for UI rendering.
+ */
+data class UiData(val title: String = "")
+
+/**
+ * Defines data to identify a Settings page.
+ */
+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,
+
+    // The display name of the page, for better readability.
+    // By default, it is the same as name.
+    val displayName: 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 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 "$displayName ${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, which is computed by name + owner + fromPage + toPage.
+    val id: Int,
+
+    // 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,
+
+    // The display name of the entry, for better readability.
+    // By default, it is $owner:$name
+    val displayName: String,
+
+    // Defines linking of Settings entries
+    val fromPage: SettingsPage? = null,
+    val toPage: SettingsPage? = null,
+
+    /**
+     * ========================================
+     * Defines entry attributes here.
+     * ========================================
+     */
+    val isAllowSearch: Boolean,
+
+    /**
+     * ========================================
+     * Defines entry APIs to get data here.
+     * ========================================
+     */
+
+    /**
+     * API to get Search related data for this entry.
+     * Returns null if this entry is not available for the search at the moment.
+     */
+    val searchData: () -> SearchData? = { null },
+
+    /**
+     * API to get UI related data for this entry.
+     * Returns null if the entry is not render-able.
+     */
+    val uiData: () -> UiData? = { null },
+
+    /**
+     * API to Render UI of this entry directly. For now, we use it in the internal injection, to
+     * support the case that the injection page owner wants to maintain both data and UI of the
+     * 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 uiLayoutImpl: (@Composable (arguments: Bundle?) -> Unit) = {},
+) {
+    fun formatAll(): String {
+        val content = listOf<String>(
+            "owner = ${owner.formatAll()}",
+            "linkFrom = ${fromPage?.formatAll()}",
+            "linkTo = ${toPage?.formatAll()}",
+        )
+        return content.joinToString("\n")
+    }
+
+    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 displayName: String? = null
+    private var arguments: Bundle? = null
+
+    fun build(): SettingsPage {
+        val normArguments = parameter.normalize(arguments)
+        return SettingsPage(
+            id = "$name:${normArguments?.toString()}".toUniqueId(),
+            name = name,
+            displayName = displayName ?: name,
+            parameter = parameter,
+            arguments = arguments,
+        )
+    }
+
+    fun setArguments(arguments: Bundle?): SettingsPageBuilder {
+        this.arguments = arguments
+        return this
+    }
+}
+
+/**
+ * The helper to build a Settings Entry instance.
+ */
+class SettingsEntryBuilder(private val name: String, private val owner: SettingsPage) {
+    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 (arguments: Bundle?) -> Unit) = {}
+
+    fun build(): SettingsEntry {
+        return SettingsEntry(
+            id = "$name:${owner.id}(${fromPage?.id}-${toPage?.id})".toUniqueId(),
+            displayName = displayName ?: "${owner.displayName}:$name",
+            name = name,
+            owner = owner,
+
+            // linking data
+            fromPage = fromPage,
+            toPage = toPage,
+
+            // attributes
+            isAllowSearch = getIsSearchable(),
+
+            // functions
+            searchData = searchDataFn,
+            uiLayoutImpl = uiLayoutFn,
+        )
+    }
+
+    fun setLink(
+        fromPage: SettingsPage? = null,
+        toPage: SettingsPage? = null
+    ): SettingsEntryBuilder {
+        if (fromPage != null) this.fromPage = fromPage
+        if (toPage != null) this.toPage = toPage
+        return this
+    }
+
+    fun setIsAllowSearch(isAllowSearch: Boolean): SettingsEntryBuilder {
+        this.isAllowSearch = isAllowSearch
+        return this
+    }
+
+    fun setSearchDataFn(fn: () -> SearchData?): SettingsEntryBuilder {
+        this.searchDataFn = fn
+        return this
+    }
+
+    fun setUiLayoutFn(fn: @Composable (arguments: Bundle?) -> Unit): SettingsEntryBuilder {
+        this.uiLayoutFn = fn
+        return this
+    }
+
+    private fun getIsSearchable(): Boolean = isAllowSearch ?: false
+
+    companion object {
+        fun create(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
+            return SettingsEntryBuilder(entryName, owner)
+        }
+
+        fun createLinkFrom(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
+            return create(entryName, owner).setLink(fromPage = owner)
+        }
+
+        fun createLinkTo(entryName: String, owner: SettingsPage): SettingsEntryBuilder {
+            return create(entryName, owner).setLink(toPage = owner)
+        }
+
+        fun createInject(owner: SettingsPage, entryName: String? = null): SettingsEntryBuilder {
+            val name = entryName ?: "${INJECT_ENTRY_NAME}_${owner.name}"
+            return createLinkTo(name, owner)
+        }
+
+        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
new file mode 100644
index 0000000..a4e5a58
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntryRepository.kt
@@ -0,0 +1,85 @@
+/*
+ * 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.common
+
+import android.util.Log
+import java.util.LinkedList
+
+private const val MAX_ENTRY_SIZE = 5000
+
+/**
+ * The repository to maintain all Settings entries
+ */
+class SettingsEntryRepository(sppRepository: SettingsPageProviderRepository) {
+    // Map of entry unique Id to entry
+    private val entryMap: Map<Int, SettingsEntry>
+
+    // Map of Settings page to its contained entries.
+    private val pageWithEntryMap: Map<Int, SettingsPageWithEntry>
+
+    init {
+        logMsg("Initialize")
+        entryMap = mutableMapOf()
+        pageWithEntryMap = mutableMapOf()
+
+        val entryQueue = LinkedList<SettingsEntry>()
+        for (page in sppRepository.getAllRootPages()) {
+            val rootEntry = SettingsEntryBuilder.createRoot(owner = page).build()
+            if (!entryMap.containsKey(rootEntry.id)) {
+                entryQueue.push(rootEntry)
+                entryMap.put(rootEntry.id, rootEntry)
+            }
+        }
+
+        while (entryQueue.isNotEmpty() && entryMap.size < MAX_ENTRY_SIZE) {
+            val entry = entryQueue.pop()
+            val page = entry.toPage
+            if (page == null || pageWithEntryMap.containsKey(page.id)) continue
+            val spp = sppRepository.getProviderOrNull(page.name) ?: continue
+            val newEntries = spp.buildEntry(page.arguments)
+            pageWithEntryMap[page.id] = SettingsPageWithEntry(page, newEntries)
+            for (newEntry in newEntries) {
+                if (!entryMap.containsKey(newEntry.id)) {
+                    entryQueue.push(newEntry)
+                    entryMap.put(newEntry.id, newEntry)
+                }
+            }
+        }
+
+        logMsg("Initialize Completed: ${entryMap.size} entries in ${pageWithEntryMap.size} pages")
+    }
+
+    fun getAllPageWithEntry(): Collection<SettingsPageWithEntry> {
+        return pageWithEntryMap.values
+    }
+
+    fun getPageWithEntry(pageId: Int): SettingsPageWithEntry? {
+        return pageWithEntryMap[pageId]
+    }
+
+    fun getAllEntries(): Collection<SettingsEntry> {
+        return entryMap.values
+    }
+
+    fun getEntry(entryId: Int): SettingsEntry? {
+        return entryMap[entryId]
+    }
+}
+
+private fun logMsg(message: String) {
+    Log.d("EntryRepo", message)
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
index 2ab0cb9..965c2b3 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
@@ -28,13 +28,13 @@
     /** The page name without arguments. */
     val name: String
 
-    /** The page arguments, default is no arguments. */
-    val arguments: List<NamedNavArgument>
+    /** The page parameters, default is no parameters. */
+    val parameter: List<NamedNavArgument>
         get() = emptyList()
 
     /** The [Composable] used to render this page. */
     @Composable
     fun Page(arguments: Bundle?)
 
-    // fun buildEntry( arguments: Bundle?) : List<entry>
+    fun buildEntry(arguments: Bundle?): List<SettingsEntry> = emptyList()
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProviderRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProviderRepository.kt
index 0a32939..6adda6b 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProviderRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProviderRepository.kt
@@ -16,24 +16,41 @@
 
 package com.android.settingslib.spa.framework.common
 
+import android.util.Log
+
 class SettingsPageProviderRepository(
-    allPagesList: List<SettingsPageProvider>,
-    private val rootPages: List<String>
+    allPageProviders: List<SettingsPageProvider>,
+    private val rootPages: List<SettingsPage> = emptyList(),
 ) {
-    // Maintains all SPA page providers.
-    private val allPages: Map<String, SettingsPageProvider> = allPagesList.associateBy { it.name }
+    // Map of page name to its provider.
+    private val pageProviderMap: Map<String, SettingsPageProvider>
+
+    init {
+        pageProviderMap = allPageProviders.associateBy { it.name }
+        logMsg("Initialize Completed: ${pageProviderMap.size} spp")
+    }
 
     fun getDefaultStartPageName(): String {
-        return rootPages.getOrElse(0) {
-            return ""
+        return if (rootPages.isNotEmpty()) {
+            rootPages[0].name
+        } else {
+            ""
         }
     }
 
+    fun getAllRootPages(): Collection<SettingsPage> {
+        return rootPages
+    }
+
     fun getAllProviders(): Collection<SettingsPageProvider> {
-        return allPages.values
+        return pageProviderMap.values
     }
 
     fun getProviderOrNull(name: String): SettingsPageProvider? {
-        return allPages[name]
+        return pageProviderMap[name]
     }
 }
+
+private fun logMsg(message: String) {
+    Log.d("SppRepo", message)
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt
index c68d5de..32ef0bb 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt
@@ -16,25 +16,35 @@
 
 package com.android.settingslib.spa.framework.compose
 
+import androidx.activity.OnBackPressedDispatcher
+import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ProvidedValue
 import androidx.compose.runtime.compositionLocalOf
 import androidx.compose.runtime.remember
 import androidx.navigation.NavHostController
 
 interface NavControllerWrapper {
     fun navigate(route: String)
-    fun navigateUp()
+    fun navigateBack()
 }
 
 @Composable
-fun NavHostController.localNavController() =
-    LocalNavController provides remember { NavControllerWrapperImpl(this) }
+fun NavHostController.localNavController(): ProvidedValue<NavControllerWrapper> {
+    val onBackPressedDispatcherOwner = LocalOnBackPressedDispatcherOwner.current
+    return LocalNavController provides remember {
+        NavControllerWrapperImpl(
+            navController = this,
+            onBackPressedDispatcher = onBackPressedDispatcherOwner?.onBackPressedDispatcher,
+        )
+    }
+}
 
 val LocalNavController = compositionLocalOf<NavControllerWrapper> {
     object : NavControllerWrapper {
         override fun navigate(route: String) {}
 
-        override fun navigateUp() {}
+        override fun navigateBack() {}
     }
 }
 
@@ -46,12 +56,13 @@
 
 internal class NavControllerWrapperImpl(
     private val navController: NavHostController,
+    private val onBackPressedDispatcher: OnBackPressedDispatcher?,
 ) : NavControllerWrapper {
     override fun navigate(route: String) {
         navController.navigate(route)
     }
 
-    override fun navigateUp() {
-        navController.navigateUp()
+    override fun navigateBack() {
+        onBackPressedDispatcher?.onBackPressed()
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
index 27fdc91..bc316f7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsColors.kt
@@ -31,6 +31,10 @@
     val secondaryText: Color = Color.Unspecified,
     val primaryContainer: Color = Color.Unspecified,
     val onPrimaryContainer: Color = Color.Unspecified,
+    val spinnerHeaderContainer: Color = Color.Unspecified,
+    val onSpinnerHeaderContainer: Color = Color.Unspecified,
+    val spinnerItemContainer: Color = Color.Unspecified,
+    val onSpinnerItemContainer: Color = Color.Unspecified,
 )
 
 internal val LocalColorScheme = staticCompositionLocalOf { SettingsColorScheme() }
@@ -65,6 +69,10 @@
         secondaryText = tonalPalette.neutralVariant30,
         primaryContainer = tonalPalette.primary90,
         onPrimaryContainer = tonalPalette.neutral10,
+        spinnerHeaderContainer = tonalPalette.primary90,
+        onSpinnerHeaderContainer = tonalPalette.neutral10,
+        spinnerItemContainer = tonalPalette.secondary90,
+        onSpinnerItemContainer = tonalPalette.neutralVariant30,
     )
 }
 
@@ -87,5 +95,9 @@
         secondaryText = tonalPalette.neutralVariant80,
         primaryContainer = tonalPalette.secondary90,
         onPrimaryContainer = tonalPalette.neutral10,
+        spinnerHeaderContainer = tonalPalette.primary90,
+        onSpinnerHeaderContainer = tonalPalette.neutral10,
+        spinnerItemContainer = tonalPalette.secondary90,
+        onSpinnerItemContainer = tonalPalette.neutralVariant30,
     )
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
index 9654368..c2223e6 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsDimension.kt
@@ -32,10 +32,17 @@
         bottom = itemPaddingVertical,
     )
     val itemPaddingAround = 8.dp
+    val itemDividerHeight = 32.dp
 
     /** The size when app icon is displayed in list. */
     val appIconItemSize = 32.dp
 
     /** The size when app icon is displayed in App info page. */
     val appIconInfoSize = 48.dp
+
+    /** The sizes info of illustration widget. */
+    val illustrationMaxWidth = 412.dp
+    val illustrationMaxHeight = 300.dp
+    val illustrationPadding = 16.dp
+    val illustrationCornerRadius = 28.dp
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt
index 04ee3c3..11af6ce 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsOpacity.kt
@@ -19,4 +19,5 @@
 object SettingsOpacity {
     const val Full = 1f
     const val Disabled = 0.38f
+    const val Divider = 0.2f
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt
index 20020d0..c66e20a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/theme/SettingsShape.kt
@@ -21,4 +21,6 @@
 
 object SettingsShape {
     val CornerMedium = RoundedCornerShape(12.dp)
+
+    val CornerLarge = RoundedCornerShape(24.dp)
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Collections.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Collections.kt
index ba25336..9478587 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Collections.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Collections.kt
@@ -19,7 +19,23 @@
 import kotlinx.coroutines.async
 import kotlinx.coroutines.awaitAll
 import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
 
+/**
+ * Performs the given [action] on each element asynchronously.
+ */
+suspend inline fun <T> Iterable<T>.asyncForEach(crossinline action: (T) -> Unit) {
+    coroutineScope {
+        forEach {
+            launch { action(it) }
+        }
+    }
+}
+
+/**
+ * Returns a list containing the results of asynchronously applying the given [transform] function
+ * to each element in the original collection.
+ */
 suspend inline fun <R, T> Iterable<T>.asyncMap(crossinline transform: (T) -> R): List<R> =
     coroutineScope {
         map { item ->
@@ -27,6 +43,11 @@
         }.awaitAll()
     }
 
+/**
+ * Returns a list containing only elements matching the given [predicate].
+ *
+ * The filter operation is done asynchronously.
+ */
 suspend inline fun <T> Iterable<T>.asyncFilter(crossinline predicate: (T) -> Boolean): List<T> =
     asyncMap { item -> item to predicate(item) }
         .filter { it.second }
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
new file mode 100644
index 0000000..aaf8107
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Parameter.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.util
+
+import android.os.Bundle
+import androidx.navigation.NamedNavArgument
+import androidx.navigation.NavType
+
+fun List<NamedNavArgument>.navRoute(): String {
+    return this.joinToString("") { argument -> "/{${argument.name}}" }
+}
+
+fun List<NamedNavArgument>.navLink(arguments: Bundle? = null): String {
+    if (arguments == null) return ""
+    val argsArray = mutableListOf<String>()
+    for (navArg in this) {
+        when (navArg.argument.type) {
+            NavType.StringType -> {
+                argsArray.add(arguments.getString(navArg.name, ""))
+            }
+            NavType.IntType -> {
+                argsArray.add(arguments.getInt(navArg.name).toString())
+            }
+        }
+    }
+    return argsArray.joinToString("") { arg -> "/$arg" }
+}
+
+fun List<NamedNavArgument>.getStringArg(name: String, arguments: Bundle? = null): String? {
+    if (this.containsStringArg(name) && arguments != null) {
+        return arguments.getString(name)
+    }
+    return null
+}
+
+fun List<NamedNavArgument>.getIntArg(name: String, arguments: Bundle? = null): Int? {
+    if (this.containsIntArg(name) && arguments != null && arguments.containsKey(name)) {
+        return arguments.getInt(name)
+    }
+    return null
+}
+
+fun List<NamedNavArgument>.containsStringArg(name: String): Boolean {
+    for (navArg in this) {
+        if (navArg.argument.type == NavType.StringType && navArg.name == name) return true
+    }
+    return false
+}
+
+fun List<NamedNavArgument>.containsIntArg(name: String): Boolean {
+    for (navArg in this) {
+        if (navArg.argument.type == NavType.IntType && navArg.name == name) return true
+    }
+    return false
+}
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
new file mode 100644
index 0000000..cd8a02a
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt
@@ -0,0 +1,102 @@
+/*
+ * 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
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+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 }
+
+/**
+ * The widget model for [Illustration] widget.
+ */
+interface IllustrationModel {
+    /**
+     * The resource id of this [Illustration].
+     */
+    val resId: Int
+
+    /**
+     * The resource type of the [Illustration].
+     *
+     * It should be Lottie or Image.
+     */
+    val resourceType: ResourceType
+}
+
+/**
+ * Illustration widget.
+ *
+ * Data is provided through [IllustrationModel].
+ */
+@Composable
+fun Illustration(model: IllustrationModel) {
+    Illustration(
+        resId = model.resId,
+        resourceType = model.resourceType,
+        modifier = Modifier,
+    )
+}
+
+@Composable
+fun Illustration(
+    resId: Int,
+    resourceType: ResourceType,
+    modifier: Modifier = Modifier
+) {
+    Column(
+        modifier = modifier
+            .fillMaxWidth()
+            .padding(horizontal = SettingsDimension.illustrationPadding),
+        horizontalAlignment = Alignment.CenterHorizontally,
+    ) {
+        val illustrationModifier = modifier
+            .sizeIn(
+                maxWidth = SettingsDimension.illustrationMaxWidth,
+                maxHeight = SettingsDimension.illustrationMaxHeight,
+            )
+            .clip(RoundedCornerShape(SettingsDimension.illustrationCornerRadius))
+            .background(color = MaterialTheme.colorScheme.surface)
+
+        when (resourceType) {
+            ResourceType.LOTTIE -> {
+                Lottie(
+                    resId = resId,
+                    modifier = illustrationModifier,
+                )
+            }
+            ResourceType.IMAGE -> {
+                ImageBox(
+                    resId = resId,
+                    contentDescription = null,
+                    modifier = illustrationModifier,
+                )
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt
similarity index 98%
rename from packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt
rename to packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt
index 0454ac3..4f77a89 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/SettingsSlider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/SettingsSlider.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.settingslib.spa.widget.ui
+package com.android.settingslib.spa.widget
 
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.AccessAlarm
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
new file mode 100644
index 0000000..f2fe7ad7
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.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.settingslib.spa.widget.preference
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.framework.compose.toState
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsShape
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+
+@Composable
+fun MainSwitchPreference(model: SwitchPreferenceModel) {
+    Surface(
+        modifier = Modifier.padding(SettingsDimension.itemPaddingEnd),
+        color = when (model.checked.value) {
+            true -> MaterialTheme.colorScheme.primaryContainer
+            else -> MaterialTheme.colorScheme.secondaryContainer
+        },
+        shape = SettingsShape.CornerLarge,
+    ) {
+        InternalSwitchPreference(
+            title = model.title,
+            checked = model.checked,
+            changeable = model.changeable,
+            onCheckedChange = model.onCheckedChange,
+            paddingStart = 20.dp,
+            paddingEnd = 20.dp,
+            paddingVertical = 18.dp,
+        )
+    }
+}
+
+@Preview
+@Composable
+fun MainSwitchPreferencePreview() {
+    SettingsTheme {
+        Column {
+            MainSwitchPreference(object : SwitchPreferenceModel {
+                override val title = "Use Dark theme"
+                override val checked = true.toState()
+                override val onCheckedChange: (Boolean) -> Unit = {}
+            })
+            MainSwitchPreference(object : SwitchPreferenceModel {
+                override val title = "Use Dark theme"
+                override val checked = false.toState()
+                override val onCheckedChange: (Boolean) -> Unit = {}
+            })
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt
new file mode 100644
index 0000000..77ea3c5
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetPreference.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.preference
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsOpacity
+
+@Composable
+internal fun TwoTargetPreference(
+    title: String,
+    summary: State<String>,
+    onClick: () -> Unit,
+    icon: @Composable (() -> Unit)? = null,
+    widget: @Composable () -> Unit,
+) {
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(end = SettingsDimension.itemPaddingEnd),
+        verticalAlignment = Alignment.CenterVertically,
+    ) {
+        Box(modifier = Modifier.weight(1f)) {
+            Preference(remember {
+                object : PreferenceModel {
+                    override val title = title
+                    override val summary = summary
+                    override val icon = icon
+                    override val onClick = onClick
+                }
+            })
+        }
+        PreferenceDivider()
+        widget()
+    }
+}
+
+@Composable
+private fun PreferenceDivider() {
+    Box(
+        Modifier
+            .padding(horizontal = SettingsDimension.itemPaddingEnd)
+            .size(width = 1.dp, height = SettingsDimension.itemDividerHeight)
+            .background(color = MaterialTheme.colorScheme.onSurface.copy(SettingsOpacity.Divider))
+    )
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
new file mode 100644
index 0000000..f1541b7
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.preference
+
+import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.widget.ui.SettingsSwitch
+
+@Composable
+fun TwoTargetSwitchPreference(
+    model: SwitchPreferenceModel,
+    icon: @Composable (() -> Unit)? = null,
+    onClick: () -> Unit,
+) {
+    TwoTargetPreference(
+        title = model.title,
+        summary = model.summary,
+        onClick = onClick,
+        icon = icon,
+    ) {
+        SettingsSwitch(
+            checked = model.checked,
+            changeable = model.changeable,
+            onCheckedChange = model.onCheckedChange,
+        )
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
index c960254..b8e4360 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/Actions.kt
@@ -26,13 +26,13 @@
 import com.android.settingslib.spa.framework.compose.LocalNavController
 
 @Composable
-internal fun NavigateUp() {
+internal fun NavigateBack() {
     val navController = LocalNavController.current
     val contentDescription = stringResource(
         id = androidx.appcompat.R.string.abc_action_bar_up_description,
     )
     BackAction(contentDescription) {
-        navController.navigateUp()
+        navController.navigateBack()
     }
 }
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
index ee453f2..1af4ce7 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SettingsScaffold.kt
@@ -26,6 +26,7 @@
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.tooling.preview.Preview
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -47,9 +48,11 @@
                     Text(
                         text = title,
                         modifier = Modifier.padding(SettingsDimension.itemPaddingAround),
+                        overflow = TextOverflow.Ellipsis,
+                        maxLines = 1,
                     )
                 },
-                navigationIcon = { NavigateUp() },
+                navigationIcon = { NavigateBack() },
                 actions = actions,
                 colors = settingsTopAppBarColors(),
             )
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Image.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Image.kt
new file mode 100644
index 0000000..0790bf8
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Image.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+
+@Composable
+fun ImageBox(
+    resId: Int,
+    contentDescription: String?,
+    modifier: Modifier = Modifier,
+) {
+    Box(
+        modifier = modifier,
+    ) {
+        Image(
+            painter = painterResource(resId),
+            contentDescription = contentDescription,
+        )
+    }
+}
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/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
new file mode 100644
index 0000000..429b81a
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.selection.selectableGroup
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.ArrowDropDown
+import androidx.compose.material.icons.outlined.ArrowDropUp
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.DropdownMenu
+import androidx.compose.material3.DropdownMenuItem
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+
+@Composable
+fun Spinner(options: List<String>, selectedIndex: Int, setIndex: (index: Int) -> Unit) {
+    if (options.isEmpty()) {
+        return
+    }
+
+    var expanded by rememberSaveable { mutableStateOf(false) }
+
+    Box(
+        modifier = Modifier
+            .padding(SettingsDimension.itemPadding)
+            .selectableGroup(),
+    ) {
+        val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
+        Button(
+            onClick = { expanded = true },
+            modifier = Modifier.height(36.dp),
+            colors = ButtonDefaults.buttonColors(
+                containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer,
+                contentColor = SettingsTheme.colorScheme.onSpinnerHeaderContainer,
+            ),
+            contentPadding = contentPadding,
+        ) {
+            SpinnerText(options[selectedIndex])
+            Icon(
+                imageVector = when {
+                    expanded -> Icons.Outlined.ArrowDropUp
+                    else -> Icons.Outlined.ArrowDropDown
+                },
+                contentDescription = null,
+            )
+        }
+        DropdownMenu(
+            expanded = expanded,
+            onDismissRequest = { expanded = false },
+            modifier = Modifier.background(SettingsTheme.colorScheme.spinnerItemContainer),
+            offset = DpOffset(x = 0.dp, y = 4.dp),
+        ) {
+            options.forEachIndexed { index, option ->
+                DropdownMenuItem(
+                    text = {
+                        SpinnerText(
+                            text = option,
+                            modifier = Modifier.padding(end = 24.dp),
+                            color = SettingsTheme.colorScheme.onSpinnerItemContainer,
+                        )
+                    },
+                    onClick = {
+                        expanded = false
+                        setIndex(index)
+                    },
+                    contentPadding = contentPadding,
+                )
+            }
+        }
+    }
+}
+
+@Composable
+private fun SpinnerText(
+    text: String,
+    modifier: Modifier = Modifier,
+    color: Color = Color.Unspecified,
+) {
+    Text(
+        text = text,
+        modifier = modifier.padding(end = SettingsDimension.itemPaddingEnd),
+        color = color,
+        style = MaterialTheme.typography.labelLarge,
+    )
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun SpinnerPreview() {
+    SettingsTheme {
+        var selectedIndex by rememberSaveable { mutableStateOf(0) }
+        Spinner(
+            options = (1..3).map { "Option $it" },
+            selectedIndex = selectedIndex,
+            setIndex = { selectedIndex = it },
+        )
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/Android.bp b/packages/SettingsLib/Spa/tests/Android.bp
index 037d8c4..1ce49fa 100644
--- a/packages/SettingsLib/Spa/tests/Android.bp
+++ b/packages/SettingsLib/Spa/tests/Android.bp
@@ -31,6 +31,7 @@
         "androidx.compose.runtime_runtime",
         "androidx.compose.ui_ui-test-junit4",
         "androidx.compose.ui_ui-test-manifest",
+        "truth-prebuilt",
     ],
     kotlincflags: ["-Xjvm-default=all"],
 }
diff --git a/packages/SettingsLib/Spa/tests/build.gradle b/packages/SettingsLib/Spa/tests/build.gradle
index be5a5ec..21d696f 100644
--- a/packages/SettingsLib/Spa/tests/build.gradle
+++ b/packages/SettingsLib/Spa/tests/build.gradle
@@ -31,6 +31,9 @@
     }
 
     sourceSets {
+        main {
+            res.srcDirs = ["res"]
+        }
         androidTest {
             kotlin {
                 srcDir "src"
@@ -63,5 +66,6 @@
     androidTestImplementation(project(":spa"))
     androidTestImplementation 'androidx.test.ext:junit-ktx:1.1.3'
     androidTestImplementation("androidx.compose.ui:ui-test-junit4:$jetpack_compose_version")
+    androidTestImplementation 'com.google.truth:truth:1.1.3'
     androidTestDebugImplementation "androidx.compose.ui:ui-test-manifest:$jetpack_compose_version"
 }
diff --git a/packages/SettingsLib/Spa/tests/res/drawable/accessibility_captioning_banner.xml b/packages/SettingsLib/Spa/tests/res/drawable/accessibility_captioning_banner.xml
new file mode 100644
index 0000000..6597ffb
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/res/drawable/accessibility_captioning_banner.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="412dp"
+    android:height="300dp"
+    android:viewportWidth="412"
+    android:viewportHeight="300">
+  <path
+      android:pathData="M383.9,300H28.1C12.6,300 0,287.4 0,271.9V28.1C0,12.6 12.6,0 28.1,0h355.8C399.4,0 412,12.6 412,28.1v243.8C412,287.4 399.4,300 383.9,300z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M79.2,179.6h53.6v8.5h-53.6z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M142.5,179.6h30.4v8.5h-30.4z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M79.2,195.5h79.2v8.5h-79.2z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M168.1,195.5h34.1v8.5h-34.1z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M211.9,195.5h34.1v8.5h-34.1z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M182.7,179.6h73.1v8.5h-73.1z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M265.5,179.6h26.8v8.5h-26.8z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M302.1,179.6h26.8v8.5h-26.8z"
+      android:fillColor="#1A73E8"/>
+  <path
+      android:pathData="M142.7,67.9h-11.5c-1.6,0 -2.9,1.3 -2.9,2.9H67.8c-7.9,0 -14.4,6.5 -14.4,14.4v132.4c0,7.9 6.5,14.4 14.4,14.4h276.4c7.9,0 14.4,-6.5 14.4,-14.4V85.2c0,-7.9 -6.5,-14.4 -14.4,-14.4H203.1c0,-1.6 -1.3,-2.9 -2.9,-2.9h-28.8c-1.6,0 -2.9,1.3 -2.9,2.9h-23C145.5,69.2 144.3,67.9 142.7,67.9zM344.2,73.7c6.4,0 11.5,5.2 11.5,11.5v132.4c0,6.3 -5.2,11.5 -11.5,11.5H67.8c-6.4,0 -11.5,-5.2 -11.5,-11.5V85.2c0,-6.3 5.2,-11.5 11.5,-11.5H344.2z"
+      android:fillColor="#DADCE0"/>
+</vector>
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
new file mode 100644
index 0000000..54abec9
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt
@@ -0,0 +1,87 @@
+/*
+ * 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
+
+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
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.R
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class IllustrationTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val DrawableId = SemanticsPropertyKey<Int>("DrawableResId")
+    private var SemanticsPropertyReceiver.drawableId by DrawableId
+
+    @Test
+    fun image_displayed() {
+        val resId = R.drawable.accessibility_captioning_banner
+        composeTestRule.setContent {
+            Illustration(
+                resId = resId,
+                resourceType = ResourceType.IMAGE,
+                modifier = Modifier.semantics { drawableId = resId }
+            )
+        }
+
+        fun hasDrawable(@DrawableRes id: Int): SemanticsMatcher =
+            SemanticsMatcher.expectValue(DrawableId, id)
+
+        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/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt
new file mode 100644
index 0000000..1d95e33
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/SettingsSliderTest.kt
@@ -0,0 +1,45 @@
+/*
+ * 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
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SettingsSliderTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun title_displayed() {
+        composeTestRule.setContent {
+            SettingsSlider(object : SettingsSliderModel {
+                override val title = "Slider"
+                override val initValue = 40
+            })
+        }
+
+        composeTestRule.onNodeWithText("Slider").assertIsDisplayed()
+    }
+
+    // TODO: Add more unit tests for SettingsSlider widget.
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/MainSwitchPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/MainSwitchPreferenceTest.kt
new file mode 100644
index 0000000..6588cf5
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/MainSwitchPreferenceTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.preference
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.isToggleable
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.compose.stateOf
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TITLE = "Title"
+
+@RunWith(AndroidJUnit4::class)
+class MainSwitchPreferenceTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun title_displayed() {
+        composeTestRule.setContent {
+            TestMainSwitchPreference(changeable = true)
+        }
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+    }
+
+    @Test
+    fun toggleable_initialStateIsCorrect() {
+        composeTestRule.setContent {
+            TestMainSwitchPreference(changeable = true)
+        }
+
+        composeTestRule.onNode(isToggleable()).assertIsOff()
+    }
+
+    @Test
+    fun click_changeable_withEffect() {
+        composeTestRule.setContent {
+            TestMainSwitchPreference(changeable = true)
+        }
+
+        composeTestRule.onNodeWithText(TITLE).performClick()
+        composeTestRule.onNode(isToggleable()).assertIsOn()
+    }
+
+    @Test
+    fun click_notChangeable_noEffect() {
+        composeTestRule.setContent {
+            TestMainSwitchPreference(changeable = false)
+        }
+
+        composeTestRule.onNodeWithText(TITLE).performClick()
+        composeTestRule.onNode(isToggleable()).assertIsOff()
+    }
+}
+
+@Composable
+private fun TestMainSwitchPreference(changeable: Boolean) {
+    val checked = rememberSaveable { mutableStateOf(false) }
+    MainSwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = TITLE
+            override val checked = checked
+            override val changeable = stateOf(changeable)
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+        }
+    })
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreferenceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreferenceTest.kt
new file mode 100644
index 0000000..c49e92d
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreferenceTest.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.settingslib.spa.widget.preference
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.isToggleable
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TwoTargetSwitchPreferenceTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun title_displayed() {
+        val checked = mutableStateOf(false)
+        composeTestRule.setContent {
+            TestTwoTargetSwitchPreference(checked = checked, changeable = true)
+        }
+
+        composeTestRule.onNodeWithText("TwoTargetSwitchPreference").assertIsDisplayed()
+    }
+
+    @Test
+    fun toggleable_initialStateIsCorrect() {
+        val checked = mutableStateOf(false)
+        composeTestRule.setContent {
+            TestTwoTargetSwitchPreference(checked = checked, changeable = true)
+        }
+
+        composeTestRule.onNode(isToggleable()).assertIsOff()
+    }
+
+    @Test
+    fun toggleable_changeable_withEffect() {
+        val checked = mutableStateOf(false)
+        composeTestRule.setContent {
+            TestTwoTargetSwitchPreference(checked = checked, changeable = true)
+        }
+
+        composeTestRule.onNode(isToggleable()).performClick()
+        composeTestRule.onNode(isToggleable()).assertIsOn()
+    }
+
+    @Test
+    fun toggleable_notChangeable_noEffect() {
+        val checked = mutableStateOf(false)
+        composeTestRule.setContent {
+            TestTwoTargetSwitchPreference(checked = checked, changeable = false)
+        }
+
+        composeTestRule.onNode(isToggleable()).performClick()
+        composeTestRule.onNode(isToggleable()).assertIsOff()
+    }
+
+    @Test
+    fun clickable_canBeClick() {
+        val checked = mutableStateOf(false)
+        var clicked = false
+        composeTestRule.setContent {
+            TestTwoTargetSwitchPreference(checked = checked, changeable = false) {
+                clicked = true
+            }
+        }
+
+        composeTestRule.onNodeWithText("TwoTargetSwitchPreference").performClick()
+        assertThat(clicked).isTrue()
+    }
+}
+
+@Composable
+private fun TestTwoTargetSwitchPreference(
+    checked: MutableState<Boolean>,
+    changeable: Boolean,
+    onClick: () -> Unit = {},
+) {
+    TwoTargetSwitchPreference(
+        model = remember {
+            object : SwitchPreferenceModel {
+                override val title = "TwoTargetSwitchPreference"
+                override val checked = checked
+                override val changeable = stateOf(changeable)
+                override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+            }
+        },
+        onClick = onClick,
+    )
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/SpinnerTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/SpinnerTest.kt
new file mode 100644
index 0000000..6c56d63
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ui/SpinnerTest.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.settingslib.spa.widget.ui
+
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SpinnerTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun spinner_initialState() {
+        var selectedIndex by mutableStateOf(0)
+        composeTestRule.setContent {
+            Spinner(
+                options = (1..3).map { "Option $it" },
+                selectedIndex = selectedIndex,
+                setIndex = { selectedIndex = it },
+            )
+        }
+
+        composeTestRule.onNodeWithText("Option 1").assertIsDisplayed()
+        composeTestRule.onNodeWithText("Option 2").assertDoesNotExist()
+        assertThat(selectedIndex).isEqualTo(0)
+    }
+
+    @Test
+    fun spinner_canChangeState() {
+        var selectedIndex by mutableStateOf(0)
+        composeTestRule.setContent {
+            Spinner(
+                options = (1..3).map { "Option $it" },
+                selectedIndex = selectedIndex,
+                setIndex = { selectedIndex = it },
+            )
+        }
+
+        composeTestRule.onNodeWithText("Option 1").performClick()
+        composeTestRule.onNodeWithText("Option 2").performClick()
+
+        composeTestRule.onNodeWithText("Option 1").assertDoesNotExist()
+        composeTestRule.onNodeWithText("Option 2").assertIsDisplayed()
+        assertThat(selectedIndex).isEqualTo(1)
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt
index 00eb60b..373b57f 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt
@@ -12,18 +12,52 @@
     val labelCollationKey: CollationKey,
 )
 
+/**
+ * Implement this interface to build an App List.
+ */
 interface AppListModel<T : AppRecord> {
+    /**
+     * Returns the spinner options available to the App List.
+     *
+     * Default no spinner will be shown.
+     */
     fun getSpinnerOptions(): List<String> = emptyList()
+
+    /**
+     * Loads the extra info for the App List, and generates the [AppRecord] List.
+     */
     fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>): Flow<List<T>>
+
+    /**
+     * Filters the [AppRecord] list.
+     *
+     * @return the [AppRecord] list which will be displayed.
+     */
     fun filter(userIdFlow: Flow<Int>, option: Int, recordListFlow: Flow<List<T>>): Flow<List<T>>
 
+    /**
+     * This function is called when the App List's loading is finished and displayed to the user.
+     *
+     * Could do some pre-cache here.
+     */
     suspend fun onFirstLoaded(recordList: List<T>) {}
+
+    /**
+     * Gets the comparator to sort the App List.
+     *
+     * Default sorting is based on the app label.
+     */
     fun getComparator(option: Int): Comparator<AppEntry<T>> = compareBy(
         { it.labelCollationKey },
         { it.record.app.packageName },
         { it.record.app.uid },
     )
 
+    /**
+     * Gets the summary for the given app record.
+     *
+     * @return null if no summary should be displayed.
+     */
     @Composable
     fun getSummary(option: Int, record: T): State<String>?
 }
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/AppsRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppsRepository.kt
index 6a64620..bb94b33 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppsRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppsRepository.kt
@@ -46,8 +46,7 @@
                     .toSet()
             }
             val flags = PackageManager.ApplicationInfoFlags.of(
-                ((if (userInfo.isAdmin) PackageManager.MATCH_ANY_USER else 0) or
-                    PackageManager.MATCH_DISABLED_COMPONENTS or
+                (PackageManager.MATCH_DISABLED_COMPONENTS or
                     PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS).toLong()
             )
             val installedApplicationsAsUser =
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 0cc497a..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,14 +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 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/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 dc30e79..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
@@ -16,7 +16,9 @@
 
 package com.android.settingslib.spaprivileged.template.app
 
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.DropdownMenu
 import androidx.compose.material3.DropdownMenuItem
@@ -32,6 +34,7 @@
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.scaffold.MoreOptionsAction
 import com.android.settingslib.spa.widget.scaffold.SettingsScaffold
+import com.android.settingslib.spa.widget.ui.Spinner
 import com.android.settingslib.spaprivileged.R
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -41,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) }
@@ -52,16 +56,20 @@
         },
     ) { paddingValues ->
         Spacer(Modifier.padding(paddingValues))
-        WorkProfilePager { userInfo ->
-            // TODO: Add a Spinner here.
-            AppList(
-                userInfo = userInfo,
-                listModel = listModel,
-                showSystem = showSystem,
-                option = stateOf(0),
-                searchQuery = stateOf(""),
-                appItem = appItem,
-            )
+        WorkProfilePager(primaryUserOnly) { userInfo ->
+            Column(Modifier.fillMaxSize()) {
+                val options = remember { listModel.getSpinnerOptions() }
+                val selectedOption = rememberSaveable { mutableStateOf(0) }
+                Spinner(options, selectedOption.value) { selectedOption.value = it }
+                AppList(
+                    userInfo = userInfo,
+                    listModel = listModel,
+                    showSystem = showSystem,
+                    option = selectedOption,
+                    searchQuery = stateOf(""),
+                    appItem = appItem,
+                )
+            }
         }
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt
new file mode 100644
index 0000000..5290bec
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt
@@ -0,0 +1,32 @@
+package com.android.settingslib.spaprivileged.template.app
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.remember
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spa.widget.preference.TwoTargetSwitchPreference
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+
+@Composable
+fun <T : AppRecord> AppListSwitchItem(
+    itemModel: AppListItemModel<T>,
+    onClick: () -> Unit,
+    checked: State<Boolean?>,
+    changeable: State<Boolean>,
+    onCheckedChange: ((newChecked: Boolean) -> Unit)?,
+) {
+    TwoTargetSwitchPreference(
+        model = remember {
+            object : SwitchPreferenceModel {
+                override val title = itemModel.label
+                override val summary = itemModel.summary
+                override val checked = checked
+                override val changeable = changeable
+                override val onCheckedChange = onCheckedChange
+            }
+        },
+        icon = { AppIcon(itemModel.record.app, SettingsDimension.appIconItemSize) },
+        onClick = onClick,
+    )
+}
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 dac79a0..c031fe8 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
@@ -26,11 +26,14 @@
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.core.os.bundleOf
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
+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.rememberContext
 import com.android.settingslib.spa.widget.preference.SwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
@@ -38,36 +41,51 @@
 import com.android.settingslib.spaprivileged.model.app.toRoute
 import kotlinx.coroutines.Dispatchers
 
-private const val NAME = "TogglePermissionAppInfoPage"
+private const val ENTRY_NAME = "AllowControl"
 private const val PERMISSION = "permission"
 private const val PACKAGE_NAME = "packageName"
 private const val USER_ID = "userId"
+private const val PAGE_NAME = "TogglePermissionAppInfoPage"
+private val PAGE_PARAMETER = listOf(
+    navArgument(PERMISSION) { type = NavType.StringType },
+    navArgument(PACKAGE_NAME) { type = NavType.StringType },
+    navArgument(USER_ID) { type = NavType.IntType },
+)
 
 internal class TogglePermissionAppInfoPageProvider(
-    private val factory: TogglePermissionAppListModelFactory,
+    private val appListTemplate: TogglePermissionAppListTemplate,
 ) : SettingsPageProvider {
-    override val name = NAME
+    override val name = PAGE_NAME
 
-    override val arguments = listOf(
-        navArgument(PERMISSION) { type = NavType.StringType },
-        navArgument(PACKAGE_NAME) { type = NavType.StringType },
-        navArgument(USER_ID) { type = NavType.IntType },
-    )
+    override val parameter = PAGE_PARAMETER
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = SettingsPage.create(name, parameter, arguments)
+        val entryList = mutableListOf<SettingsEntry>()
+        entryList.add(
+            SettingsEntryBuilder.create(ENTRY_NAME, owner).setIsAllowSearch(false).build()
+        )
+        return entryList
+    }
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        checkNotNull(arguments)
-        val permission = checkNotNull(arguments.getString(PERMISSION))
-        val packageName = checkNotNull(arguments.getString(PACKAGE_NAME))
+        val permissionType = arguments?.getString(PERMISSION)!!
+        val packageName = arguments.getString(PACKAGE_NAME)!!
         val userId = arguments.getInt(USER_ID)
-        val listModel = rememberContext { context -> factory.createModel(permission, context) }
+        val listModel = appListTemplate.rememberModel(permissionType)
         TogglePermissionAppInfoPage(listModel, packageName, userId)
     }
 
     companion object {
         @Composable
         internal fun navigator(permissionType: String, app: ApplicationInfo) =
-            navigator(route = "$NAME/$permissionType/${app.toRoute()}")
+            navigator(route = "$PAGE_NAME/$permissionType/${app.toRoute()}")
+
+        internal fun buildPageData(permissionType: String): SettingsPage {
+            return SettingsPage.create(
+                PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
+        }
     }
 }
 
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
new file mode 100644
index 0000000..4c748b8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppList.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.ui.res.stringResource
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.rememberContext
+import com.android.settingslib.spa.framework.util.asyncMapItem
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Implement this interface to build an App List which toggles a permission on / off.
+ */
+interface TogglePermissionAppListModel<T : AppRecord> {
+    val pageTitleResId: Int
+    val switchTitleResId: Int
+    val footerResId: Int
+
+    /**
+     * Loads the extra info for the App List, and generates the [AppRecord] List.
+     *
+     * Default is implemented by [transformItem]
+     */
+    fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>): Flow<List<T>> =
+        appListFlow.asyncMapItem(::transformItem)
+
+    /**
+     * Loads the extra info for one app, and generates the [AppRecord].
+     *
+     * This must be implemented, because when show the App Info page for single app, this will be
+     * used instead of [transform].
+     */
+    fun transformItem(app: ApplicationInfo): T
+
+    /**
+     * Filters the [AppRecord] list.
+     *
+     * @return the [AppRecord] list which will be displayed.
+     */
+    fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<T>>): Flow<List<T>>
+
+    /**
+     * Gets whether the permission is allowed for the given app.
+     */
+    @Composable
+    fun isAllowed(record: T): State<Boolean?>
+
+    /**
+     * Gets whether the permission on / off is changeable for the given app.
+     */
+    fun isChangeable(record: T): Boolean
+
+    /**
+     * Sets whether the permission is allowed for the given app.
+     */
+    fun setAllowed(record: T, newAllowed: Boolean)
+}
+
+interface TogglePermissionAppListProvider {
+    val permissionType: String
+
+    fun createModel(context: Context): TogglePermissionAppListModel<out AppRecord>
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return TogglePermissionAppListPageProvider.buildInjectEntry(permissionType)
+    }
+
+    @Composable
+    fun EntryItem() {
+        val listModel = rememberContext(::createModel)
+        Preference(
+            object : PreferenceModel {
+                override val title = stringResource(listModel.pageTitleResId)
+                override val onClick = TogglePermissionAppListPageProvider.navigator(permissionType)
+            }
+        )
+    }
+
+    /**
+     * Gets the route to the toggle permission App List page.
+     *
+     * Expose route to enable enter from non-SPA pages.
+     */
+    fun getRoute(): String =
+        TogglePermissionAppListPageProvider.getRoute(permissionType)
+}
+
+class TogglePermissionAppListTemplate(
+    allProviders: List<TogglePermissionAppListProvider>,
+) {
+    private val listModelProviderMap = allProviders.associateBy { it.permissionType }
+
+    fun createPageProviders(): List<SettingsPageProvider> = listOf(
+        TogglePermissionAppListPageProvider(this),
+        TogglePermissionAppInfoPageProvider(this),
+    )
+
+    @Composable
+    internal fun rememberModel(permissionType: String) = rememberContext { context ->
+        listModelProviderMap.getValue(permissionType).createModel(context)
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt
deleted file mode 100644
index e1354bd..0000000
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListModel.kt
+++ /dev/null
@@ -1,75 +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.settingslib.spaprivileged.template.app
-
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.ui.res.stringResource
-import com.android.settingslib.spa.framework.common.SettingsPageProvider
-import com.android.settingslib.spa.framework.compose.rememberContext
-import com.android.settingslib.spa.framework.util.asyncMapItem
-import com.android.settingslib.spa.widget.preference.Preference
-import com.android.settingslib.spa.widget.preference.PreferenceModel
-import com.android.settingslib.spaprivileged.model.app.AppRecord
-import kotlinx.coroutines.flow.Flow
-
-interface TogglePermissionAppListModel<T : AppRecord> {
-    val pageTitleResId: Int
-    val switchTitleResId: Int
-    val footerResId: Int
-
-    fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>): Flow<List<T>> =
-        appListFlow.asyncMapItem(::transformItem)
-
-    fun transformItem(app: ApplicationInfo): T
-    fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<T>>): Flow<List<T>>
-
-    @Composable
-    fun isAllowed(record: T): State<Boolean?>
-
-    fun isChangeable(record: T): Boolean
-    fun setAllowed(record: T, newAllowed: Boolean)
-}
-
-interface TogglePermissionAppListModelFactory {
-    fun createModel(
-        permission: String,
-        context: Context,
-    ): TogglePermissionAppListModel<out AppRecord>
-
-    fun createPageProviders(): List<SettingsPageProvider> = listOf(
-        TogglePermissionAppListPageProvider(this),
-        TogglePermissionAppInfoPageProvider(this),
-    )
-
-    @Composable
-    fun EntryItem(permissionType: String) {
-        val listModel = rememberModel(permissionType)
-        Preference(
-            object : PreferenceModel {
-                override val title = stringResource(listModel.pageTitleResId)
-                override val onClick = TogglePermissionAppListPageProvider.navigator(permissionType)
-            }
-        )
-    }
-}
-
-@Composable
-internal fun TogglePermissionAppListModelFactory.rememberModel(permission: String) =
-    rememberContext { context -> createModel(permission, context) }
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 6d00d56..65cc4f9 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
@@ -25,37 +25,59 @@
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
+import androidx.core.os.bundleOf
 import androidx.navigation.NavType
 import androidx.navigation.navArgument
+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.util.getStringArg
 import com.android.settingslib.spaprivileged.R
 import com.android.settingslib.spaprivileged.model.app.AppListModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import kotlinx.coroutines.flow.Flow
 
-private const val NAME = "TogglePermissionAppList"
+private const val ENTRY_NAME = "AppList"
 private const val PERMISSION = "permission"
+private const val PAGE_NAME = "TogglePermissionAppList"
+private val PAGE_PARAMETER = listOf(
+    navArgument(PERMISSION) { type = NavType.StringType },
+)
 
 internal class TogglePermissionAppListPageProvider(
-    private val factory: TogglePermissionAppListModelFactory,
+    private val appListTemplate: TogglePermissionAppListTemplate,
 ) : SettingsPageProvider {
-    override val name = NAME
+    override val name = PAGE_NAME
 
-    override val arguments = listOf(
-        navArgument(PERMISSION) { type = NavType.StringType },
-    )
+    override val parameter = PAGE_PARAMETER
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val permissionType = parameter.getStringArg(PERMISSION, arguments)!!
+        val appListPage = SettingsPage.create(name, parameter, arguments)
+        val appInfoPage = TogglePermissionAppInfoPageProvider.buildPageData(permissionType)
+        val entryList = mutableListOf<SettingsEntry>()
+        // TODO: add more categories, such as personal, work, cloned, etc.
+        for (category in listOf("personal")) {
+            entryList.add(
+                SettingsEntryBuilder.createLinkFrom("${ENTRY_NAME}_$category", appListPage)
+                    .setLink(toPage = appInfoPage)
+                    .setIsAllowSearch(false)
+                    .build()
+            )
+        }
+        return entryList
+    }
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        checkNotNull(arguments)
-        val permissionType = checkNotNull(arguments.getString(PERMISSION))
-        TogglePermissionAppList(permissionType)
+        TogglePermissionAppList(arguments?.getString(PERMISSION)!!)
     }
 
     @Composable
     private fun TogglePermissionAppList(permissionType: String) {
-        val listModel = factory.rememberModel(permissionType)
+        val listModel = appListTemplate.rememberModel(permissionType)
         val context = LocalContext.current
         val internalListModel = remember {
             TogglePermissionInternalAppListModel(context, listModel)
@@ -75,8 +97,21 @@
     }
 
     companion object {
+        /**
+         * Gets the route to this page.
+         *
+         * Expose route to enable enter from non-SPA pages.
+         */
+        internal fun getRoute(permissionType: String) = "$PAGE_NAME/$permissionType"
+
         @Composable
-        internal fun navigator(permissionType: String) = navigator(route = "$NAME/$permissionType")
+        internal fun navigator(permissionType: String) = navigator(route = getRoute(permissionType))
+
+        internal fun buildInjectEntry(permissionType: String): SettingsEntryBuilder {
+            val appListPage = SettingsPage.create(
+                PAGE_NAME, PAGE_PARAMETER, bundleOf(PERMISSION to permissionType))
+            return SettingsEntryBuilder.createInject(owner = appListPage).setIsAllowSearch(false)
+        }
     }
 }
 
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/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/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4a67adb..494ec1e 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"እስኪሞላ ድረስ <xliff:g id="TIME">%1$s</xliff:g> ይቀራል"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - እስኪሞላ ድረስ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ኃይል መሙላት ባለበት ቆሟል"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"ኃይል በዝግታ በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"በገመድ-አልባ ኃይል በመሙላት ላይ"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ባትሪ እየሞላ አይደለም"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"ተገናኝቷል፣ ኃይል በመሙላት ላይ አይደለም"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"ባትሪ ሞልቷል"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 3683014..d7d09dd 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিং পজ কৰা হৈছে"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"লাহে লাহে চাৰ্জ হৈছে"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"বেতাঁৰৰ মাধ্যমেৰে চাৰ্জ হৈ আছে"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"চ্চাৰ্জ কৰা নাই"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"সংযোগ হৈ আছে, চাৰ্জ হৈ থকা নাই"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"চাৰ্জ হ’ল"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 66baea6..2f1b7d7 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Да поўнай зарадкі засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – да поўнай зарадкі засталося: <xliff:g id="TIME">%2$s</xliff:g>"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Зарадка прыпынена"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Павольная зарадка"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бесправадная зарадка"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Ідзе зарадка"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не зараджаецца"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Падключана, не зараджаецца"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Зараджаны"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 833fe15..9082210 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -408,8 +408,7 @@
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Die Größe aller Aktivitäten darf, ungeachtet der Manifestwerte, für die Mehrfensterdarstellung angepasst werden"</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Freiform-Fenster zulassen"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Unterstützung für experimentelle Freiform-Fenster aktivieren"</string>
-    <!-- no translation found for desktop_mode (2389067840550544462) -->
-    <skip />
+    <string name="desktop_mode" msgid="2389067840550544462">"Desktopmodus"</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Passwort für Desktop-Sicherung"</string>
     <string name="local_backup_password_summary_none" msgid="7646898032616361714">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt"</string>
     <string name="local_backup_password_summary_change" msgid="1707357670383995567">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen tippen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 243ecaa..c0b8a27 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -668,7 +668,7 @@
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"اگر <xliff:g id="SWITCHAPP">%1$s</xliff:g> را همه‌فرستی کنید یا خروجی را تغییر دهید، همه‌فرستی کنونی متوقف خواهد شد"</string>
     <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"همه‌فرستی <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
     <string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"تغییر خروجی"</string>
-    <string name="back_navigation_animation" msgid="8105467568421689484">"پویانمایی‌های اشاره برگشت پیش‌بینانه"</string>
-    <string name="back_navigation_animation_summary" msgid="741292224121599456">"پویانمایی‌های سیستم را برای اشاره برگشت پیش‌بینانه فعال کنید."</string>
+    <string name="back_navigation_animation" msgid="8105467568421689484">"پویانمایی‌های اشاره برگشت پیش‌گویانه"</string>
+    <string name="back_navigation_animation_summary" msgid="741292224121599456">"پویانمایی‌های سیستم را برای اشاره برگشت پیش‌گویانه فعال کنید."</string>
     <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"‏این تنظیم پویانمایی‌های سیستم را برای پویانمایی اشاره برگشت پیش‌بینانه فعال می‌کند. این تنظیم مستلزم تنظیم شدن enableOnBackInvokedCallback مربوط به هر برنامه روی صحیح در فایل مانیفست است."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index e268331..66373b5 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kunnes täynnä"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataus on keskeytetty"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Hidas lataus"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Langaton lataus"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Ladataan"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei laturissa"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Yhdistetty, ei ladata"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Ladattu"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index a925bd0..f1acddae 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -211,15 +211,17 @@
     <string name="tts_general_section_title" msgid="8919671529502364567">"Général"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Réinitialiser la hauteur de la voix du texte"</string>
     <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Rétablir la hauteur normale à laquelle le texte est énoncé."</string>
-    <!-- no translation found for tts_rate_entries:0 (4563475121751694801) -->
-    <!-- no translation found for tts_rate_entries:1 (6323184326270638754) -->
-    <!-- no translation found for tts_rate_entries:2 (2569200872125313769) -->
-    <!-- no translation found for tts_rate_entries:3 (9010794089704942570) -->
-    <!-- no translation found for tts_rate_entries:4 (4634010129655810634) -->
-    <!-- no translation found for tts_rate_entries:5 (8929490998534497543) -->
-    <!-- no translation found for tts_rate_entries:6 (8442352376763286772) -->
-    <!-- no translation found for tts_rate_entries:7 (4446831566506165093) -->
-    <!-- no translation found for tts_rate_entries:8 (6946761421234586000) -->
+  <string-array name="tts_rate_entries">
+    <item msgid="4563475121751694801">"60 %"</item>
+    <item msgid="6323184326270638754">"80 %"</item>
+    <item msgid="2569200872125313769">"100 %"</item>
+    <item msgid="9010794089704942570">"150 %"</item>
+    <item msgid="4634010129655810634">"200 %"</item>
+    <item msgid="8929490998534497543">"250 %"</item>
+    <item msgid="8442352376763286772">"300 %"</item>
+    <item msgid="4446831566506165093">"350 %"</item>
+    <item msgid="6946761421234586000">"400 %"</item>
+  </string-array>
     <string name="choose_profile" msgid="343803890897657450">"Sélectionnez un profil"</string>
     <string name="category_personal" msgid="6236798763159385225">"Personnel"</string>
     <string name="category_work" msgid="4014193632325996115">"Professionnel"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 8c99837..30ef44e 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> para completar a carga)"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: a carga está en pausa"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Cargando lentamente"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Cargando sen fíos"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Cargando"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Non se está cargando"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Conectado, sen cargar"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Cargada"</string>
@@ -670,7 +668,7 @@
     <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"Se emites contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g> ou cambias de saída, a emisión en curso deterase"</string>
     <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Emitir contido a través de <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
     <string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Cambiar de saída"</string>
-    <string name="back_navigation_animation" msgid="8105467568421689484">"Animacións para o xesto preditivo de volver atrás"</string>
-    <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activa as animacións do sistema para o xesto preditivo de volver atrás."</string>
-    <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta opción de configuración activa as animacións do sistema para o xesto preditivo de volver atrás. É preciso definir enableOnBackInvokedCallback como True (verdadeiro) para cada aplicación no ficheiro de manifesto."</string>
+    <string name="back_navigation_animation" msgid="8105467568421689484">"Animacións de retroceso preditivo"</string>
+    <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activa as animacións do sistema para o retroceso preditivo."</string>
+    <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Esta opción de configuración activa as animacións xestuais preditivas. É preciso definir enableOnBackInvokedCallback como True (verdadeiro) para cada aplicación no ficheiro de manifesto."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 2e7b30b..4affd4f 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցված է"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Դանդաղ լիցքավորում"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Անլար լիցքավորում"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Լիցքավորում"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Չի լիցքավորվում"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Միացված է, չի լիցքավորվում"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Լիցքավորված է"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 42ac063..b541d50 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> fram að fullri hleðslu"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> fram að fullri hleðslu"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Hlé var gert á hleðslu"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Hæg hleðsla"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Hleður þráðlaust"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Í hleðslu"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Ekki í hleðslu"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Tengt, ekki í hleðslu"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Fullhlaðin"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index d80d708..7bfa1c4 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបពេញ"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ការសាកថ្មត្រូវបានផ្អាក"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងសាក​ថ្ម"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"កំពុង​សាកថ្មយឺត"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"កំពុង​សាកថ្ម​ឥតខ្សែ"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"កំពុងសាកថ្ម"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"មិនកំពុង​សាក​ថ្ម"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"បានភ្ជាប់ មិនកំពុង​សាកថ្ម"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"បាន​សាក​ថ្មពេញ"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index ed7cdd2..d5dc291 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -195,7 +195,7 @@
     <string name="tts_default_lang_summary" msgid="9042620014800063470">"Текстти окуй турган тилди тандоо"</string>
     <string name="tts_play_example_title" msgid="1599468547216481684">"Үлгүнү угуу"</string>
     <string name="tts_play_example_summary" msgid="634044730710636383">"Кепти синтездөөнүн кыскача көргөзмөсүн ойнотуу"</string>
-    <string name="tts_install_data_title" msgid="1829942496472751703">"Үн дайындарын орнотуу"</string>
+    <string name="tts_install_data_title" msgid="1829942496472751703">"Үнгө байланыштуу нерселерди орнотуу"</string>
     <string name="tts_install_data_summary" msgid="3608874324992243851">"Кеп синтезине керектүү үн дайындарын орнотуңуз"</string>
     <string name="tts_engine_security_warning" msgid="3372432853837988146">"Бул кепти синтездөө каражаты бардык айтыла турган текстти, анын ичинде сырсөздөр жана насыя карточкасынын номери сыяктуу жеке маалыматты, топтошу мүмкүн. Ал <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> каражатынан алынат. Бул кепти синтездөө каражаты колдонулсунбу?"</string>
     <string name="tts_engine_network_required" msgid="8722087649733906851">"Бул тилде кеп синтезаторун иштетүү үчүн Интернетке туташуу керек."</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index e0efe21..e87422d 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -201,9 +201,9 @@
     <string name="tts_engine_network_required" msgid="8722087649733906851">"या भाषेस टेक्‍स्‍ट टू स्‍पीचसाठी एका नेटवर्क कनेक्शनची आवश्यकता आहे."</string>
     <string name="tts_default_sample_string" msgid="6388016028292967973">"हे उच्चार संश्लेषणाचे एक उदाहरण आहे"</string>
     <string name="tts_status_title" msgid="8190784181389278640">"डीफॉल्ट भाषा स्थिती"</string>
-    <string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> पूर्णपणे समर्थित आहे"</string>
+    <string name="tts_status_ok" msgid="8583076006537547379">"<xliff:g id="LOCALE">%1$s</xliff:g> ला पूर्ण सपोर्ट आहे"</string>
     <string name="tts_status_requires_network" msgid="8327617638884678896">"<xliff:g id="LOCALE">%1$s</xliff:g> ला नेटवर्क कनेक्शनची आवश्यकता आहे"</string>
-    <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> समर्थित नाही"</string>
+    <string name="tts_status_not_supported" msgid="2702997696245523743">"<xliff:g id="LOCALE">%1$s</xliff:g> ला सपोर्ट नाही"</string>
     <string name="tts_status_checking" msgid="8026559918948285013">"तपासत आहे..."</string>
     <string name="tts_engine_settings_title" msgid="7849477533103566291">"<xliff:g id="TTS_ENGINE_NAME">%s</xliff:g> साठी सेटिंग्ज"</string>
     <string name="tts_engine_settings_button" msgid="477155276199968948">"इंजीन सेटिंग्ज लाँच करा"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 98bff9ed..1384d5b 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do pełnego naładowania"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – ładowanie zostało wstrzymane"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Wolne ładowanie"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Ładowanie bezprzewodowe"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Ładowanie"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nie podłączony"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Podłączono, brak ładowania"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Naładowana"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index 41a5965..987b9c3 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -120,13 +120,13 @@
     <item msgid="8946330945963372966">"96,0 kHz"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-    <item msgid="2574107108483219051">"Folosiți selectarea sistemului (prestabilit)"</item>
+    <item msgid="2574107108483219051">"Folosește selectarea sistemului (prestabilit)"</item>
     <item msgid="4671992321419011165">"16 biți/eșantion"</item>
     <item msgid="1933898806184763940">"24 biți/eșantion"</item>
     <item msgid="1212577207279552119">"32 biți/eșantion"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
-    <item msgid="9196208128729063711">"Folosiți selectarea sistemului (prestabilit)"</item>
+    <item msgid="9196208128729063711">"Folosește selectarea sistemului (prestabilit)"</item>
     <item msgid="1084497364516370912">"16 biți/eșantion"</item>
     <item msgid="2077889391457961734">"24 biți/eșantion"</item>
     <item msgid="3836844909491316925">"32 biți/eșantion"</item>
@@ -137,7 +137,7 @@
     <item msgid="927546067692441494">"Stereo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
-    <item msgid="1997302811102880485">"Folosiți selectarea sistemului (prestabilit)"</item>
+    <item msgid="1997302811102880485">"Folosește selectarea sistemului (prestabilit)"</item>
     <item msgid="8005696114958453588">"Mono"</item>
     <item msgid="1333279807604675720">"Stereo"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index e9f4030..8b6259c 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -74,14 +74,14 @@
     <string name="private_dns_broken" msgid="1984159464346556931">"Serverul DNS privat nu poate fi accesat"</string>
     <string name="wifi_limited_connection" msgid="1184778285475204682">"Conexiune limitată"</string>
     <string name="wifi_status_no_internet" msgid="3799933875988829048">"Fără conexiune la internet"</string>
-    <string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Trebuie să vă conectați"</string>
+    <string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Trebuie să te conectezi"</string>
     <string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"Punctul de acces este temporar plin"</string>
     <string name="connected_via_carrier" msgid="1968057009076191514">"Conectată prin %1$s"</string>
     <string name="available_via_carrier" msgid="465598683092718294">"Disponibilă prin %1$s"</string>
     <string name="osu_opening_provider" msgid="4318105381295178285">"Se deschide <xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g>"</string>
     <string name="osu_connect_failed" msgid="9107873364807159193">"Nu s-a putut conecta"</string>
     <string name="osu_completing_sign_up" msgid="8412636665040390901">"Se finalizează înscrierea…"</string>
-    <string name="osu_sign_up_failed" msgid="5605453599586001793">"Nu s-a putut finaliza înscrierea. Atingeți pentru a încerca din nou."</string>
+    <string name="osu_sign_up_failed" msgid="5605453599586001793">"Nu s-a putut finaliza înscrierea. Atinge pentru a încerca din nou."</string>
     <string name="osu_sign_up_complete" msgid="7640183358878916847">"Înscrierea a fost finalizată. Se conectează…"</string>
     <string name="speed_label_very_slow" msgid="8526005255731597666">"Foarte lentă"</string>
     <string name="speed_label_slow" msgid="6069917670665664161">"Lentă"</string>
@@ -118,7 +118,7 @@
     <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispozitiv de intrare"</string>
     <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acces la internet"</string>
     <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"Acces la agendă și istoricul apelurilor"</string>
-    <string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Folosiți pentru accesul la agendă și istoricul apelurilor"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"Folosește pentru accesul la agendă și istoricul apelurilor"</string>
     <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Distribuirea conexiunii la internet"</string>
     <string name="bluetooth_profile_map" msgid="8907204701162107271">"Mesaje text"</string>
     <string name="bluetooth_profile_sap" msgid="8304170950447934386">"Acces la SIM"</string>
@@ -138,17 +138,17 @@
     <string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Conectat la dispoz. pt. acces internet"</string>
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Acces la internet local"</string>
     <string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"Folosește pentru acces la internet"</string>
-    <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Utilizați pentru hartă"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"Folosește pentru hartă"</string>
     <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"Folosiți pentru acces la SIM"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="7324694226276491807">"Folosește pentru profilul pentru conținut media audio"</string>
     <string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"Folosește pentru componenta audio a telefonului"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"Folosește pentru transferul de fișiere"</string>
     <string name="bluetooth_hid_profile_summary_use_for" msgid="4289460627406490952">"Utilizați pentru introducere date"</string>
     <string name="bluetooth_hearing_aid_profile_summary_use_for" msgid="7689393730163320483">"Folosiți pentru aparatele auditive"</string>
-    <string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Folosiți pentru LE_AUDIO"</string>
-    <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Asociați"</string>
-    <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"CONECTAȚI"</string>
-    <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Anulați"</string>
+    <string name="bluetooth_le_audio_profile_summary_use_for" msgid="2778318636027348572">"Folosește pentru LE_AUDIO"</string>
+    <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Asociază"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"CONECTEAZĂ"</string>
+    <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Anulează"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Asocierea dispozitivelor îți permite accesul la persoanele de contact și la istoricul apelurilor când dispozitivul este conectat."</string>
     <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Nu s-a putut împerechea cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Nu s-a putut asocia cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> din cauza unui cod PIN sau a unei chei de acces incorecte."</string>
@@ -194,10 +194,10 @@
     <string name="tts_lang_not_selected" msgid="7927823081096056147">"Nu ai selectat limba"</string>
     <string name="tts_default_lang_summary" msgid="9042620014800063470">"Setează vocea caracteristică limbii pentru textul vorbit"</string>
     <string name="tts_play_example_title" msgid="1599468547216481684">"Ascultă un exemplu"</string>
-    <string name="tts_play_example_summary" msgid="634044730710636383">"Redați o demonstrație scurtă a sintetizării vorbirii"</string>
-    <string name="tts_install_data_title" msgid="1829942496472751703">"Instalați date vocale"</string>
-    <string name="tts_install_data_summary" msgid="3608874324992243851">"Instalați datele vocale necesare pentru sintetizarea vorbirii"</string>
-    <string name="tts_engine_security_warning" msgid="3372432853837988146">"Acest motor de sintetizare a vorbirii poate culege în întregime textul vorbit, inclusiv datele personale cum ar fi parolele și numerele cărților de credit. Metoda provine de la motorul <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Permiteți utilizarea acestui motor de sintetizare a vorbirii?"</string>
+    <string name="tts_play_example_summary" msgid="634044730710636383">"Redă o demonstrație scurtă a sintetizării vorbirii"</string>
+    <string name="tts_install_data_title" msgid="1829942496472751703">"Instalează date vocale"</string>
+    <string name="tts_install_data_summary" msgid="3608874324992243851">"Instalează datele vocale necesare pentru sintetizarea vorbirii"</string>
+    <string name="tts_engine_security_warning" msgid="3372432853837988146">"Acest motor de sintetizare a vorbirii poate culege în întregime textul vorbit, inclusiv datele personale cum ar fi parolele și numerele cărților de credit. Metoda provine de la motorul <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g>. Permiți utilizarea acestui motor de sintetizare a vorbirii?"</string>
     <string name="tts_engine_network_required" msgid="8722087649733906851">"Pentru rezultatul transformării textului în vorbire pentru această limbă este necesară o conexiune de rețea care să funcționeze."</string>
     <string name="tts_default_sample_string" msgid="6388016028292967973">"Acesta este un exemplu de sintetizare a vorbirii"</string>
     <string name="tts_status_title" msgid="8190784181389278640">"Starea limbii prestabilite"</string>
@@ -210,7 +210,7 @@
     <string name="tts_engine_preference_section_title" msgid="3861562305498624904">"Motor preferat"</string>
     <string name="tts_general_section_title" msgid="8919671529502364567">"Preferințe generale"</string>
     <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Resetează tonalitatea vorbirii"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Resetați tonalitatea cu care se rostește textul în mod prestabilit."</string>
+    <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Resetează tonalitatea cu care se rostește textul în mod prestabilit."</string>
   <string-array name="tts_rate_entries">
     <item msgid="4563475121751694801">"60 %"</item>
     <item msgid="6323184326270638754">"80 %"</item>
@@ -227,7 +227,7 @@
     <string name="category_work" msgid="4014193632325996115">"Serviciu"</string>
     <string name="development_settings_title" msgid="140296922921597393">"Opțiuni pentru dezvoltatori"</string>
     <string name="development_settings_enable" msgid="4285094651288242183">"Activează opțiunile pentru dezvoltatori"</string>
-    <string name="development_settings_summary" msgid="8718917813868735095">"Setați opțiuni pentru dezvoltarea aplicației"</string>
+    <string name="development_settings_summary" msgid="8718917813868735095">"Setează opțiuni pentru dezvoltarea aplicației"</string>
     <string name="development_settings_not_available" msgid="355070198089140951">"Opțiunile de dezvoltator nu sunt disponibile pentru acest utilizator"</string>
     <string name="vpn_settings_not_available" msgid="2894137119965668920">"Setările VPN nu sunt disponibile pentru acest utilizator"</string>
     <string name="tethering_settings_not_available" msgid="266821736434699780">"Setările pentru tethering nu sunt disponibile pentru acest utilizator"</string>
@@ -240,14 +240,14 @@
     <string name="adb_wireless_error" msgid="721958772149779856">"Eroare"</string>
     <string name="adb_wireless_settings" msgid="2295017847215680229">"Remedierea erorilor wireless"</string>
     <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Activează remedierea erorilor wireless pentru a vedea și a folosi dispozitivele disponibile"</string>
-    <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Asociați dispozitivul folosind codul QR"</string>
+    <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Asociază dispozitivul folosind codul QR"</string>
     <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Asociază dispozitive noi folosind scannerul de coduri QR"</string>
     <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Asociază dispozitivul folosind codul de conectare"</string>
     <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Asociază dispozitive noi folosind codul din șase cifre"</string>
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispozitive asociate"</string>
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Conectat"</string>
     <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Detalii despre dispozitiv"</string>
-    <string name="adb_device_forget" msgid="193072400783068417">"Ștergeți"</string>
+    <string name="adb_device_forget" msgid="193072400783068417">"Șterge"</string>
     <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Amprenta pentru dispozitiv: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
     <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Conectare nereușită"</string>
     <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Asigură-te că ai conectat <xliff:g id="DEVICE_NAME">%1$s</xliff:g> la rețeaua corectă"</string>
@@ -261,17 +261,17 @@
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Adresa IP și portul"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Scanează codul QR"</string>
     <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Asociază dispozitivul prin Wi-Fi scanând un cod QR"</string>
-    <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conectați-vă la o rețea Wi-Fi"</string>
+    <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Conectează-te la o rețea Wi-Fi"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, remedierea erorilor, dev"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"Comandă rapidă pentru raportul de erori"</string>
     <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Afișează un buton în meniul de pornire pentru a realiza un raport de erori"</string>
     <string name="keep_screen_on" msgid="1187161672348797558">"Activ permanent"</string>
     <string name="keep_screen_on_summary" msgid="1510731514101925829">"Ecranul nu va fi inactiv pe durata încărcării"</string>
     <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Activează jurnalul de examinare HCI Bluetooth"</string>
-    <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Înregistrați pachetele Bluetooth. (Comutați Bluetooth după modificarea setării)"</string>
+    <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Înregistrează pachetele Bluetooth. (Comutați Bluetooth după modificarea setării)"</string>
     <string name="oem_unlock_enable" msgid="5334869171871566731">"Deblocarea OEM"</string>
-    <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Permiteți deblocarea bootloaderului"</string>
-    <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permiteți deblocarea OEM?"</string>
+    <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Permite deblocarea bootloaderului"</string>
+    <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"Permiți deblocarea OEM?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"AVERTISMENT: funcțiile de protecție a dispozitivului nu vor funcționa pe acest dispozitiv cât timp setarea este activată."</string>
     <string name="mock_location_app" msgid="6269380172542248304">"Selectează aplicația pentru locația de testare"</string>
     <string name="mock_location_app_not_set" msgid="6972032787262831155">"Nicio aplicație setată pentru locația de testare"</string>
@@ -284,7 +284,7 @@
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Date mobile permanent active"</string>
     <string name="tethering_hardware_offload" msgid="4116053719006939161">"Accelerare hardware pentru tethering"</string>
     <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișează dispozitivele Bluetooth fără nume"</string>
-    <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Dezactivați volumul absolut"</string>
+    <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Dezactivează volumul absolut"</string>
     <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activează Gabeldorsche"</string>
     <string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versiunea AVRCP pentru Bluetooth"</string>
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selectează versiunea AVRCP pentru Bluetooth"</string>
@@ -303,7 +303,7 @@
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="7274396574659784285">"Declanșați codecul LDAC audio pentru Bluetooth\nSelecție: calitatea redării"</string>
     <string name="bluetooth_select_a2dp_codec_streaming_label" msgid="2040810756832027227">"Transmitere în flux: <xliff:g id="STREAMING_PARAMETER">%1$s</xliff:g>"</string>
     <string name="select_private_dns_configuration_title" msgid="7887550926056143018">"DNS privat"</string>
-    <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Selectați modul DNS privat"</string>
+    <string name="select_private_dns_configuration_dialog_title" msgid="3731422918335951912">"Selectează modul DNS privat"</string>
     <string name="private_dns_mode_off" msgid="7065962499349997041">"Dezactivat"</string>
     <string name="private_dns_mode_opportunistic" msgid="1947864819060442354">"Automat"</string>
     <string name="private_dns_mode_provider" msgid="3619040641762557028">"Nume de gazdă al furnizorului de DNS privat"</string>
@@ -321,18 +321,18 @@
     <string name="dev_logpersist_clear_warning_message" msgid="6447590867594287413">"Când nu mai monitorizăm folosind jurnalul permanent, trebuie să ștergem datele de jurnal aflate pe dispozitivul tău."</string>
     <string name="select_logpersist_title" msgid="447071974007104196">"Stochează date jurnal permanent pe dispozitiv"</string>
     <string name="select_logpersist_dialog_title" msgid="7745193591195485594">"Selectează zonele-tampon ale jurnalului de stocat permanent pe dispozitiv"</string>
-    <string name="select_usb_configuration_title" msgid="6339801314922294586">"Selectați configurația USB"</string>
-    <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"Selectați configurația USB"</string>
-    <string name="allow_mock_location" msgid="2102650981552527884">"Permiteți locațiile fictive"</string>
+    <string name="select_usb_configuration_title" msgid="6339801314922294586">"Selectează configurația USB"</string>
+    <string name="select_usb_configuration_dialog_title" msgid="3579567144722589237">"Selectează configurația USB"</string>
+    <string name="allow_mock_location" msgid="2102650981552527884">"Permite locațiile fictive"</string>
     <string name="allow_mock_location_summary" msgid="179780881081354579">"Permite locațiile fictive"</string>
     <string name="debug_view_attributes" msgid="3539609843984208216">"Activează inspectarea atributelor de vizualizare"</string>
     <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Păstrați întotdeauna conexiunea de date mobile activată, chiar și atunci când funcția Wi‑Fi este activată (pentru comutarea rapidă între rețele)."</string>
-    <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Folosiți accelerarea hardware pentru tethering, dacă este disponibilă"</string>
+    <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Folosește accelerarea hardware pentru tethering, dacă este disponibilă"</string>
     <string name="adb_warning_title" msgid="7708653449506485728">"Permiteți remedierea erorilor prin USB?"</string>
     <string name="adb_warning_message" msgid="8145270656419669221">"Remedierea erorilor prin USB are exclusiv scopuri de dezvoltare. Utilizați-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string>
-    <string name="adbwifi_warning_title" msgid="727104571653031865">"Permiteți remedierea erorilor wireless?"</string>
-    <string name="adbwifi_warning_message" msgid="8005936574322702388">"Remedierea erorilor wireless are exclusiv scopuri de dezvoltare. Folosiți-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string>
-    <string name="adb_keys_warning_message" msgid="2968555274488101220">"Revocați accesul la remedierea erorilor prin USB de pe toate computerele pe care le-ați autorizat anterior?"</string>
+    <string name="adbwifi_warning_title" msgid="727104571653031865">"Permiți remedierea erorilor wireless?"</string>
+    <string name="adbwifi_warning_message" msgid="8005936574322702388">"Remedierea erorilor wireless are exclusiv scopuri de dezvoltare. Folosește-o pentru a copia date de pe computer pe dispozitiv, pentru a instala aplicații pe dispozitiv fără notificare și pentru a citi datele din jurnale."</string>
+    <string name="adb_keys_warning_message" msgid="2968555274488101220">"Revoci accesul la remedierea erorilor prin USB de pe toate computerele pe care le-ai autorizat anterior?"</string>
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"Permiți setările pentru dezvoltare?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul tău și aplicațiile de pe acesta să nu mai funcționeze sau să funcționeze necorespunzător."</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Verificați aplicațiile prin USB"</string>
@@ -347,9 +347,9 @@
     <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"Configurează verif. HDCP"</string>
     <string name="debug_debugging_category" msgid="535341063709248842">"Depanare"</string>
     <string name="debug_app" msgid="8903350241392391766">"Selectează aplicația de depanare"</string>
-    <string name="debug_app_not_set" msgid="1934083001283807188">"Nu ați setat o aplicație de depanare"</string>
+    <string name="debug_app_not_set" msgid="1934083001283807188">"Nu ai setat o aplicație de depanare"</string>
     <string name="debug_app_set" msgid="6599535090477753651">"Aplicație de depanare: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="select_application" msgid="2543228890535466325">"Selectați o aplicație"</string>
+    <string name="select_application" msgid="2543228890535466325">"Selectează o aplicație"</string>
     <string name="no_application" msgid="9038334538870247690">"Niciuna"</string>
     <string name="wait_for_debugger" msgid="7461199843335409809">"Așteaptă depanatorul"</string>
     <string name="wait_for_debugger_summary" msgid="6846330006113363286">"Înaintea executării, aplicația așteaptă atașarea depanatorului"</string>
@@ -362,8 +362,8 @@
     <string name="strict_mode_summary" msgid="1838248687233554654">"Iluminare intermitentă la operații lungi pe firul principal"</string>
     <string name="pointer_location" msgid="7516929526199520173">"Locația indicatorului"</string>
     <string name="pointer_location_summary" msgid="957120116989798464">"Suprapunere care indică date curente pt. atingeri"</string>
-    <string name="show_touches" msgid="8437666942161289025">"Afișați atingerile"</string>
-    <string name="show_touches_summary" msgid="3692861665994502193">"Afișați feedbackul vizual pentru atingeri"</string>
+    <string name="show_touches" msgid="8437666942161289025">"Afișează atingerile"</string>
+    <string name="show_touches_summary" msgid="3692861665994502193">"Afișează feedbackul vizual pentru atingeri"</string>
     <string name="show_screen_updates" msgid="2078782895825535494">"Actualizări suprafețe"</string>
     <string name="show_screen_updates_summary" msgid="2126932969682087406">"Iluminarea întregii fereastre la actualizare"</string>
     <string name="show_hw_screen_updates" msgid="2021286231267747506">"Afiș. actualizări ecran"</string>
@@ -371,14 +371,14 @@
     <string name="show_hw_layers_updates" msgid="5268370750002509767">"Actualiz. strat. hardware"</string>
     <string name="show_hw_layers_updates_summary" msgid="5850955890493054618">"Straturile hardware clipesc verde la actualizare"</string>
     <string name="debug_hw_overdraw" msgid="8944851091008756796">"Remediază suprapunerea"</string>
-    <string name="disable_overlays" msgid="4206590799671557143">"Dezactivați suprapun. HW"</string>
+    <string name="disable_overlays" msgid="4206590799671557143">"Dezactiv. suprapuneri HW"</string>
     <string name="disable_overlays_summary" msgid="1954852414363338166">"Folosește mereu GPU pentru compunerea ecranului"</string>
     <string name="simulate_color_space" msgid="1206503300335835151">"Simulează spațiu culoare"</string>
     <string name="enable_opengl_traces_title" msgid="4638773318659125196">"Monitorizări OpenGL"</string>
     <string name="usb_audio_disable_routing" msgid="3367656923544254975">"Dezactivați rutarea audio USB"</string>
     <string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Dezact. rutarea automată către perif. audio USB"</string>
     <string name="debug_layout" msgid="1659216803043339741">"Afișează limite aspect"</string>
-    <string name="debug_layout_summary" msgid="8825829038287321978">"Afișați limitele clipului, marginile etc."</string>
+    <string name="debug_layout_summary" msgid="8825829038287321978">"Afișează limitele clipului, marginile etc."</string>
     <string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"Direcție aspect dreapta - stânga"</string>
     <string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"Direcție obligatorie aspect ecran dreapta - stânga"</string>
     <string name="window_blurs" msgid="6831008984828425106">"Permite estompări la nivel de fereastră"</string>
@@ -386,24 +386,24 @@
     <string name="force_msaa_summary" msgid="9070437493586769500">"Activează MSAA 4x în aplicațiile OpenGL ES 2.0"</string>
     <string name="show_non_rect_clip" msgid="7499758654867881817">"Remediezi decupări nerectangulare"</string>
     <string name="track_frame_time" msgid="522674651937771106">"Profil redare cu HWUI"</string>
-    <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Activați nivelurile de depanare GPU"</string>
-    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permiteți încărcarea nivelurilor de depanare GPU pentru aplicațiile de depanare"</string>
+    <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Activează nivelurile de depanare GPU"</string>
+    <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Permite încărcarea nivelurilor de depanare GPU pentru aplicațiile de depanare"</string>
     <string name="enable_verbose_vendor_logging" msgid="1196698788267682072">"Activează înregistrarea detaliată a furnizorilor"</string>
-    <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Includeți alte jurnale ale furnizorilor de dispozitive în rapoartele de eroare, care pot conține informații private, folosiți mai multă baterie și/sau mai mult spațiu de stocare."</string>
+    <string name="enable_verbose_vendor_logging_summary" msgid="5426292185780393708">"Include alte jurnale ale furnizorilor de dispozitive în rapoartele de eroare, care pot conține informații private, folosește mai multă baterie și/sau mai mult spațiu de stocare."</string>
     <string name="window_animation_scale_title" msgid="5236381298376812508">"Scară animație fereastră"</string>
     <string name="transition_animation_scale_title" msgid="1278477690695439337">"Scară tranziție animații"</string>
     <string name="animator_duration_scale_title" msgid="7082913931326085176">"Scară durată Animator"</string>
     <string name="overlay_display_devices_title" msgid="5411894622334469607">"Simulați afișaje secundare"</string>
     <string name="debug_applications_category" msgid="5394089406638954196">"Aplicații"</string>
-    <string name="immediately_destroy_activities" msgid="1826287490705167403">"Nu păstrați activitățile"</string>
+    <string name="immediately_destroy_activities" msgid="1826287490705167403">"Nu păstra activitățile"</string>
     <string name="immediately_destroy_activities_summary" msgid="6289590341144557614">"Elimină activitățile imediat ce utilizatorul le închide"</string>
     <string name="app_process_limit_title" msgid="8361367869453043007">"Limită procese fundal"</string>
-    <string name="show_all_anrs" msgid="9160563836616468726">"Afișați ANR de fundal"</string>
+    <string name="show_all_anrs" msgid="9160563836616468726">"Afișează ANR de fundal"</string>
     <string name="show_all_anrs_summary" msgid="8562788834431971392">"Afișează dialogul Aplicația nu răspunde pentru aplicațiile din fundal"</string>
     <string name="show_notification_channel_warnings" msgid="3448282400127597331">"Afișează avertismentele de pe canalul de notificări"</string>
     <string name="show_notification_channel_warnings_summary" msgid="68031143745094339">"Afișează avertisment pe ecran când o aplicație postează o notificare fără canal valid"</string>
     <string name="force_allow_on_external" msgid="9187902444231637880">"Forțează accesul aplicațiilor la stocarea externă"</string>
-    <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permiteți scrierea oricărei aplicații eligibile în stocarea externă, indiferent de valorile manifestului"</string>
+    <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Permite scrierea oricărei aplicații eligibile în stocarea externă, indiferent de valorile manifestului"</string>
     <string name="force_resizable_activities" msgid="7143612144399959606">"Forțați redimensionarea activităților"</string>
     <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permiteți redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activează ferestrele cu formă liberă"</string>
@@ -428,13 +428,13 @@
   </string-array>
     <string name="inactive_apps_title" msgid="5372523625297212320">"Aplicații în standby"</string>
     <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Inactivă. Atinge pentru a comuta."</string>
-    <string name="inactive_app_active_summary" msgid="8047630990208722344">"Activă. Atingeți pentru a comuta."</string>
+    <string name="inactive_app_active_summary" msgid="8047630990208722344">"Activă. Atinge pentru a comuta."</string>
     <string name="standby_bucket_summary" msgid="5128193447550429600">"Stare Standby aplicații: <xliff:g id="BUCKET"> %s</xliff:g>"</string>
     <string name="transcode_settings_title" msgid="2581975870429850549">"Setări pentru transcodarea conținutului media"</string>
     <string name="transcode_user_control" msgid="6176368544817731314">"Modifică setările prestabilite de transcodare"</string>
     <string name="transcode_enable_all" msgid="2411165920039166710">"Activează transcodarea"</string>
     <string name="transcode_default" msgid="3784803084573509491">"Presupune că aplicațiile acceptă formatele moderne"</string>
-    <string name="transcode_notification" msgid="5560515979793436168">"Vedeți notificările privind transcodarea"</string>
+    <string name="transcode_notification" msgid="5560515979793436168">"Vezi notificările privind transcodarea"</string>
     <string name="transcode_disable_cache" msgid="3160069309377467045">"Dezactivează memoria cache pentru transcodare"</string>
     <string name="runningservices_settings_title" msgid="6460099290493086515">"Servicii în curs de funcționare"</string>
     <string name="runningservices_settings_summary" msgid="1046080643262665743">"Vezi și controlează serviciile care funcționează în prezent"</string>
@@ -442,7 +442,7 @@
     <string name="select_webview_provider_dialog_title" msgid="2444261109877277714">"Setează implementarea WebView"</string>
     <string name="select_webview_provider_toast_text" msgid="8512254949169359848">"Această opțiune nu mai este validă. Încearcă din nou."</string>
     <string name="picture_color_mode" msgid="1013807330552931903">"Modul de culori pentru imagini"</string>
-    <string name="picture_color_mode_desc" msgid="151780973768136200">"Folosiți sRGB"</string>
+    <string name="picture_color_mode_desc" msgid="151780973768136200">"Folosește sRGB"</string>
     <string name="daltonizer_mode_disabled" msgid="403424372812399228">"Dezactivat"</string>
     <string name="daltonizer_mode_monochromacy" msgid="362060873835885014">"Daltonism"</string>
     <string name="daltonizer_mode_deuteranomaly" msgid="3507284319584683963">"Deuteranomalie (roșu-verde)"</string>
@@ -515,7 +515,7 @@
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"Metode active de introducere de text"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"Folosește limbile sistemului"</string>
     <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"Deschiderea setărilor pentru <xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> a eșuat"</string>
-    <string name="ime_security_warning" msgid="6547562217880551450">"Această metodă de introducere de text poate culege în întregime textul introdus, inclusiv datele personale, cum ar fi parolele și numerele cardurilor de credit. Metoda provine de la aplicația <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Utilizați această metodă de introducere de text?"</string>
+    <string name="ime_security_warning" msgid="6547562217880551450">"Această metodă de introducere de text poate culege în întregime textul introdus, inclusiv datele personale, cum ar fi parolele și numerele cardurilor de credit. Metoda provine de la aplicația <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g>. Folosești această metodă de introducere de text?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"Notă: după repornire, această aplicație nu poate porni până nu deblochezi telefonul"</string>
     <string name="ims_reg_title" msgid="8197592958123671062">"Situația înregistrării IMS"</string>
     <string name="ims_reg_status_registered" msgid="884916398194885457">"Înregistrat"</string>
@@ -538,13 +538,13 @@
     <string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"Niciodată"</string>
     <string name="zen_interruption_level_priority" msgid="5392140786447823299">"Numai cu prioritate"</string>
     <string name="zen_mode_and_condition" msgid="8877086090066332516">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
-    <string name="zen_alarm_warning_indef" msgid="4146527909616457163">"Dacă nu dezactivați această opțiune înainte, nu veți auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
+    <string name="zen_alarm_warning_indef" msgid="4146527909616457163">"Dacă nu dezactivezi această opțiune înainte, nu vei auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="245729928048586280">"Nu vei auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="3346777418136233330">"la <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="6382760514842998629">"<xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="zen_mode_duration_settings_title" msgid="1553451650289651489">"Durată"</string>
     <string name="zen_mode_duration_always_prompt_title" msgid="3212996860498119555">"Întreabă de fiecare dată"</string>
-    <string name="zen_mode_forever" msgid="3339224497605461291">"Până când dezactivați"</string>
+    <string name="zen_mode_forever" msgid="3339224497605461291">"Până când dezactivezi"</string>
     <string name="time_unit_just_now" msgid="3006134267292728099">"Chiar acum"</string>
     <string name="media_transfer_this_device_name" product="default" msgid="2357329267148436433">"Acest telefon"</string>
     <string name="media_transfer_this_device_name" product="tablet" msgid="3714653244000242800">"Această tabletă"</string>
@@ -554,7 +554,7 @@
     <string name="help_label" msgid="3528360748637781274">"Ajutor și feedback"</string>
     <string name="storage_category" msgid="2287342585424631813">"Stocare"</string>
     <string name="shared_data_title" msgid="1017034836800864953">"Date la care se permite accesul"</string>
-    <string name="shared_data_summary" msgid="5516326713822885652">"Vedeți și modificați datele la care se permite accesul"</string>
+    <string name="shared_data_summary" msgid="5516326713822885652">"Vezi și modifică datele la care se permite accesul"</string>
     <string name="shared_data_no_blobs_text" msgid="3108114670341737434">"Nu există date la care se permite accesul pentru acest utilizator."</string>
     <string name="shared_data_query_failure_text" msgid="3489828881998773687">"A apărut o eroare la preluarea datelor la care se permite accesul. Încearcă din nou."</string>
     <string name="blob_id_text" msgid="8680078988996308061">"ID-ul datelor la care se permite accesul: <xliff:g id="BLOB_ID">%d</xliff:g>"</string>
@@ -567,15 +567,15 @@
     <string name="delete_blob_text" msgid="2819192607255625697">"Șterge datele la care se permite accesul"</string>
     <string name="delete_blob_confirmation_text" msgid="7807446938920827280">"Sigur ștergi aceste date la care se permite accesul?"</string>
     <string name="user_add_user_item_summary" msgid="5748424612724703400">"Utilizatorii dețin aplicații și materiale proprii"</string>
-    <string name="user_add_profile_item_summary" msgid="5418602404308968028">"Puteți restricționa accesul la aplicații și la conținut din contul dvs."</string>
+    <string name="user_add_profile_item_summary" msgid="5418602404308968028">"Poți restricționa accesul la aplicații și la conținut din contul tău"</string>
     <string name="user_add_user_item_title" msgid="2394272381086965029">"Utilizator"</string>
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"Profil limitat"</string>
-    <string name="user_add_user_title" msgid="5457079143694924885">"Adăugați un utilizator nou?"</string>
-    <string name="user_add_user_message_long" msgid="1527434966294733380">"Puteți să permiteți accesul la acest dispozitiv altor persoane creând utilizatori suplimentari. Fiecare utilizator are propriul spațiu, pe care îl poate personaliza cu aplicații, imagini de fundal etc. De asemenea, utilizatorii pot ajusta setările dispozitivului, cum ar fi setările pentru Wi-Fi, care îi afectează pe toți ceilalți utilizatori.\n\nDupă ce adăugați un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOricare dintre utilizatori poate actualiza aplicațiile pentru toți ceilalți utilizatori. Este posibil ca setările de accesibilitate și serviciile să nu se transfere la noul utilizator."</string>
-    <string name="user_add_user_message_short" msgid="3295959985795716166">"Când adăugați un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOrice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
+    <string name="user_add_user_title" msgid="5457079143694924885">"Adaugi un utilizator nou?"</string>
+    <string name="user_add_user_message_long" msgid="1527434966294733380">"Poți să permiți accesul la acest dispozitiv altor persoane creând utilizatori suplimentari. Fiecare utilizator are propriul spațiu, pe care îl poate personaliza cu aplicații, imagini de fundal etc. De asemenea, utilizatorii pot ajusta setările dispozitivului, cum ar fi setările pentru Wi-Fi, care îi afectează pe toți ceilalți utilizatori.\n\nDupă ce adaugi un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOricare dintre utilizatori poate actualiza aplicațiile pentru toți ceilalți utilizatori. Este posibil ca setările de accesibilitate și serviciile să nu se transfere la noul utilizator."</string>
+    <string name="user_add_user_message_short" msgid="3295959985795716166">"Când adaugi un utilizator nou, acesta trebuie să-și configureze spațiul.\n\nOrice utilizator poate actualiza aplicațiile pentru toți ceilalți utilizatori."</string>
     <string name="user_setup_dialog_title" msgid="8037342066381939995">"Configurați utilizatorul acum?"</string>
-    <string name="user_setup_dialog_message" msgid="269931619868102841">"Asigurați-vă că utilizatorul are posibilitatea de a prelua dispozitivul și de a-și configura spațiul"</string>
-    <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Configurați profilul acum?"</string>
+    <string name="user_setup_dialog_message" msgid="269931619868102841">"Asigură-te că utilizatorul are posibilitatea de a prelua dispozitivul și de a-și configura spațiul"</string>
+    <string name="user_setup_profile_dialog_message" msgid="4788197052296962620">"Configurezi profilul acum?"</string>
     <string name="user_setup_button_setup_now" msgid="1708269547187760639">"Configurați acum"</string>
     <string name="user_setup_button_setup_later" msgid="8712980133555493516">"Nu acum"</string>
     <string name="user_add_user_type_title" msgid="551279664052914497">"Adaugă"</string>
@@ -583,49 +583,49 @@
     <string name="user_new_profile_name" msgid="2405500423304678841">"Profil nou"</string>
     <string name="user_info_settings_title" msgid="6351390762733279907">"Info. utilizator"</string>
     <string name="profile_info_settings_title" msgid="105699672534365099">"Informații de profil"</string>
-    <string name="user_need_lock_message" msgid="4311424336209509301">"Înainte de a putea crea un profil cu permisiuni limitate, va trebui să configurați blocarea ecranului pentru a vă proteja aplicațiile și datele personale."</string>
-    <string name="user_set_lock_button" msgid="1427128184982594856">"Configurați blocarea"</string>
+    <string name="user_need_lock_message" msgid="4311424336209509301">"Înainte de a putea crea un profil cu permisiuni limitate, va trebui să configurezi blocarea ecranului pentru a-ți proteja aplicațiile și datele personale."</string>
+    <string name="user_set_lock_button" msgid="1427128184982594856">"Configurează blocarea"</string>
     <string name="user_switch_to_user" msgid="6975428297154968543">"Treci la <xliff:g id="USER_NAME">%s</xliff:g>"</string>
     <string name="creating_new_user_dialog_message" msgid="7232880257538970375">"Se creează un utilizator nou…"</string>
     <string name="creating_new_guest_dialog_message" msgid="1114905602181350690">"Se creează un invitat nou…"</string>
     <string name="add_user_failed" msgid="4809887794313944872">"Nu s-a creat noul utilizator"</string>
     <string name="add_guest_failed" msgid="8074548434469843443">"Nu s-a putut crea un invitat nou"</string>
     <string name="user_nickname" msgid="262624187455825083">"Pseudonim"</string>
-    <string name="user_add_user" msgid="7876449291500212468">"Adăugați un utilizator"</string>
+    <string name="user_add_user" msgid="7876449291500212468">"Adaugă un utilizator"</string>
     <string name="guest_new_guest" msgid="3482026122932643557">"Adăugați un invitat"</string>
     <string name="guest_exit_guest" msgid="5908239569510734136">"Ștergeți invitatul"</string>
     <string name="guest_reset_guest" msgid="6110013010356013758">"Resetezi sesiunea pentru invitați"</string>
     <string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"Resetezi invitatul?"</string>
     <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"Excludeți invitatul?"</string>
-    <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetați"</string>
-    <string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Eliminați"</string>
+    <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"Resetează"</string>
+    <string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"Elimină"</string>
     <string name="guest_resetting" msgid="7822120170191509566">"Se resetează invitatul…"</string>
-    <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Resetați sesiunea pentru invitați?"</string>
+    <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"Resetezi sesiunea pentru invitați?"</string>
     <string name="guest_reset_and_restart_dialog_message" msgid="2764425635305200790">"Astfel, va începe o nouă sesiune pentru invitați și se vor șterge toate aplicațiile și datele din sesiunea actuală"</string>
-    <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Ieșiți din modul pentru invitați?"</string>
+    <string name="guest_exit_dialog_title" msgid="1846494656849381804">"Ieși din modul pentru invitați?"</string>
     <string name="guest_exit_dialog_message" msgid="1743218864242719783">"Se vor șterge toate aplicațiile și datele din sesiunea pentru invitați actuală"</string>
     <string name="guest_exit_dialog_button" msgid="1736401897067442044">"Ieșiți"</string>
     <string name="guest_exit_dialog_title_non_ephemeral" msgid="7675327443743162986">"Salvezi activitatea invitatului?"</string>
     <string name="guest_exit_dialog_message_non_ephemeral" msgid="223385323235719442">"Salvează activitatea din sesiunea actuală sau șterge aplicațiile și datele"</string>
-    <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Ștergeți"</string>
-    <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salvați"</string>
-    <string name="guest_exit_button" msgid="5774985819191803960">"Ieșiți din modul pentru invitați"</string>
+    <string name="guest_exit_clear_data_button" msgid="3425812652180679014">"Șterge"</string>
+    <string name="guest_exit_save_data_button" msgid="3690974510644963547">"Salvează"</string>
+    <string name="guest_exit_button" msgid="5774985819191803960">"Ieși din modul pentru invitați"</string>
     <string name="guest_reset_button" msgid="2515069346223503479">"Resetează sesiunea pentru invitați"</string>
-    <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Ieșiți din modul pentru invitați"</string>
+    <string name="guest_exit_quick_settings_button" msgid="1912362095913765471">"Ieși din modul pentru invitați"</string>
     <string name="guest_notification_ephemeral" msgid="7263252466950923871">"Toate activitățile vor fi șterse la ieșire"</string>
     <string name="guest_notification_non_ephemeral" msgid="6843799963012259330">"Puteți să salvați sau să ștergeți activitatea la ieșire"</string>
-    <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetați pentru a șterge acum activitatea din sesiune sau salvați ori ștergeți activitatea la ieșire"</string>
+    <string name="guest_notification_non_ephemeral_non_first_login" msgid="8009307983766934876">"Resetează pentru a șterge acum activitatea din sesiune sau salvează ori șterge activitatea la ieșire"</string>
     <string name="user_image_take_photo" msgid="467512954561638530">"Fă o fotografie"</string>
-    <string name="user_image_choose_photo" msgid="1363820919146782908">"Alegeți o imagine"</string>
+    <string name="user_image_choose_photo" msgid="1363820919146782908">"Alege o imagine"</string>
     <string name="user_image_photo_selector" msgid="433658323306627093">"Selectați fotografia"</string>
     <string name="failed_attempts_now_wiping_device" msgid="4016329172216428897">"Prea multe încercări incorecte. Datele de pe acest dispozitiv vor fi șterse."</string>
     <string name="failed_attempts_now_wiping_user" msgid="469060411789668050">"Prea multe încercări incorecte. Acest utilizator va fi șters."</string>
     <string name="failed_attempts_now_wiping_profile" msgid="7626589520888963129">"Prea multe încercări incorecte. Acest profil de serviciu și datele sale vor fi șterse."</string>
-    <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Respingeți"</string>
+    <string name="failed_attempts_now_wiping_dialog_dismiss" msgid="2749889771223578925">"Respinge"</string>
     <string name="cached_apps_freezer_device_default" msgid="2616594131750144342">"Prestabilit pentru dispozitiv"</string>
     <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dezactivat"</string>
     <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string>
-    <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să reporniți dispozitivul. Reporniți-l acum sau anulați."</string>
+    <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să repornești dispozitivul. Repornește-l acum sau anulează."</string>
     <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string>
     <string name="wifi_hotspot_switch_on_text" msgid="9212273118217786155">"Activat"</string>
     <string name="wifi_hotspot_switch_off_text" msgid="7245567251496959764">"Dezactivat"</string>
@@ -656,7 +656,7 @@
     <string name="accessibility_ethernet_disconnected" msgid="2832501530856497489">"Ethernet deconectat."</string>
     <string name="accessibility_ethernet_connected" msgid="6175942685957461563">"Ethernet."</string>
     <string name="accessibility_no_calling" msgid="3540827068323895748">"Apelarea nu este disponibilă."</string>
-    <string name="avatar_picker_title" msgid="8492884172713170652">"Alegeți o fotografie de profil"</string>
+    <string name="avatar_picker_title" msgid="8492884172713170652">"Alege o fotografie de profil"</string>
     <string name="default_user_icon_description" msgid="6554047177298972638">"Pictograma prestabilită a utilizatorului"</string>
     <string name="physical_keyboard_title" msgid="4811935435315835220">"Tastatură fizică"</string>
     <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"Alege aspectul tastaturii"</string>
@@ -669,6 +669,6 @@
     <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"Difuzează <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
     <string name="bt_le_audio_broadcast_dialog_different_output" msgid="2638402023060391333">"Schimbă rezultatul"</string>
     <string name="back_navigation_animation" msgid="8105467568421689484">"Animații pentru gestul înapoi predictiv"</string>
-    <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activați animațiile de sistem pentru gestul înapoi predictiv."</string>
+    <string name="back_navigation_animation_summary" msgid="741292224121599456">"Activează animațiile de sistem pentru gestul înapoi predictiv."</string>
     <string name="back_navigation_animation_dialog" msgid="8696966520944625596">"Această setare activează animațiile de sistem pentru animația gesturilor predictive. Necesită setarea valorii true în cazul atributului enableOnBackInvokedCallback pentru fiecare aplicație în fișierul manifest."</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 4387a41..8abc51a 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"සම්පූර්ණ වීමට <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරියි"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - සම්පූර්ණ වීමට <xliff:g id="TIME">%2$s</xliff:g>ක් ඉතිරියි"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය විරාම කර ඇත"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"සෙමින් ආරෝපණය"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"නොරැහැන්ව ආරෝපණය වේ"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"ආරෝපණය වේ"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"ආරෝපණය නොවේ"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"සම්බන්ධයි, ආරෝපණය නොවේ"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"අරෝපිතයි"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index b116bd4..515f963 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> derisa të mbushet"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të mbushet"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi është vendosur në pauzë"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Karikim i shpejtë"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Po karikohet ngadalë"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Po karikohet pa tel"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Po karikohet"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Nuk po karikohet"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Lidhur, jo në karikim"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Karikuar"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 8457ef0..943ba5f6 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kvar tills fulladdat"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kvar tills fulladdat"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har pausats"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Laddas långsamt"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Laddas trådlöst"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Laddas"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Laddar inte"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Ansluten, laddas inte"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Laddat"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 6ed8f42..b7124a63 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> zimesalia ijae chaji"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Imesitisha kuchaji"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Inachaji pole pole"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Inachaji bila kutumia waya"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Inachaji"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Haichaji"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Imeunganishwa, haichaji"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Imechajiwa"</string>
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-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 118542f..de88c2c 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tamamen şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: Şarj işlemi duraklatıldı"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Yavaş şarj oluyor"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Kablosuz şarj oluyor"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Şarj Etme"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Şarj olmuyor"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Bağlandı, şarj olmuyor"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Şarj oldu"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 817fa35..a438741 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -477,15 +477,13 @@
     <string name="power_charging" msgid="6727132649743436802">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
-    <!-- no translation found for power_charging_limited (6971664137170239141) -->
-    <skip />
+    <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Заряджання призупинено"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
     <string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Повільне заряджання"</string>
     <string name="battery_info_status_charging_wireless" msgid="8924722966861282197">"Бездротове заряджання"</string>
-    <!-- no translation found for battery_info_status_charging_dock (8573274094093364791) -->
-    <skip />
+    <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"Заряджання"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Не заряджається"</string>
     <string name="battery_info_status_not_charging" msgid="3371084153747234837">"Підключено, не заряджається"</string>
     <string name="battery_info_status_full" msgid="1339002294876531312">"Заряджено"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 1940986..91b852a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -43,8 +43,6 @@
 public class A2dpProfile implements LocalBluetoothProfile {
     private static final String TAG = "A2dpProfile";
 
-    private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U
-
     private Context mContext;
 
     private BluetoothA2dp mService;
@@ -83,12 +81,13 @@
                 device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED);
                 device.refresh();
             }
-            mIsProfileReady=true;
+            mIsProfileReady = true;
             mProfileManager.callServiceConnectedListeners();
         }
 
         public void onServiceDisconnected(int profile) {
-            mIsProfileReady=false;
+            mIsProfileReady = false;
+            mProfileManager.callServiceDisconnectedListeners();
         }
     }
 
@@ -333,7 +332,7 @@
             case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LC3:
                 index = 6;
                 break;
-            case SOURCE_CODEC_TYPE_OPUS: // TODO update in U
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS:
                 index = 7;
                 break;
            }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 62c83cf..51812f0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -367,8 +367,14 @@
             if (bondState == BluetoothDevice.BOND_NONE) {
                 // Check if we need to remove other Coordinated set member devices / Hearing Aid
                 // devices
+                if (DEBUG) {
+                    Log.d(TAG, "BondStateChangedHandler: cachedDevice.getGroupId() = "
+                            + cachedDevice.getGroupId() + ", cachedDevice.getHiSyncId()= "
+                            + cachedDevice.getHiSyncId());
+                }
                 if (cachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID
                         || cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
+                    Log.d(TAG, "BondStateChangedHandler: Start onDeviceUnpaired");
                     mDeviceManager.onDeviceUnpaired(cachedDevice);
                 }
                 int reason = intent.getIntExtra(BluetoothDevice.EXTRA_UNBOND_REASON,
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 32d5b78..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;
     }
 
@@ -1431,11 +1434,10 @@
      * first connected device in the coordinated set, and then switch the content of the main
      * device and member devices.
      *
-     * @param prevMainDevice the previous Main device, it will be added into the member device set.
-     * @param newMainDevice the new Main device, it will be removed from the member device set.
+     * @param newMainDevice the new Main device which is from the previous main device's member
+     *                      list.
      */
-    public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
-            CachedBluetoothDevice newMainDevice) {
+    public void switchMemberDeviceContent(CachedBluetoothDevice newMainDevice) {
         // Backup from main device
         final BluetoothDevice tmpDevice = mDevice;
         final short tmpRssi = mRssi;
@@ -1444,8 +1446,7 @@
         mDevice = newMainDevice.mDevice;
         mRssi = newMainDevice.mRssi;
         mJustDiscovered = newMainDevice.mJustDiscovered;
-        addMemberDevice(prevMainDevice);
-        mMemberDevices.remove(newMainDevice);
+
         // Set sub device from backup
         newMainDevice.mDevice = tmpDevice;
         newMainDevice.mRssi = tmpRssi;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index cd3242a..5662ce6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -17,6 +17,7 @@
 package com.android.settingslib.bluetooth;
 
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
@@ -317,12 +318,14 @@
     }
 
     public synchronized void onDeviceUnpaired(CachedBluetoothDevice device) {
+        device.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
         CachedBluetoothDevice mainDevice = mCsipDeviceManager.findMainDevice(device);
         final Set<CachedBluetoothDevice> memberDevices = device.getMemberDevice();
         if (!memberDevices.isEmpty()) {
             // Main device is unpaired, to unpair the member device
             for (CachedBluetoothDevice memberDevice : memberDevices) {
                 memberDevice.unpair();
+                memberDevice.setGroupId(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
                 device.removeMemberDevice(memberDevice);
             }
         } else if (mainDevice != null) {
@@ -354,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 fc70ba4..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;
             }
         }
@@ -231,7 +234,7 @@
                         // When both LE Audio devices are disconnected, receiving member device
                         // connection. To switch content and dispatch to notify UI change
                         mBtManager.getEventManager().dispatchDeviceRemoved(mainDevice);
-                        mainDevice.switchMemberDeviceContent(mainDevice, cachedDevice);
+                        mainDevice.switchMemberDeviceContent(cachedDevice);
                         mainDevice.refresh();
                         // It is necessary to do remove and add for updating the mapping on
                         // preference and device
@@ -255,10 +258,11 @@
 
                 for (CachedBluetoothDevice device: memberSet) {
                     if (device.isConnected()) {
+                        log("set device: " + device + " as the main device");
                         // Main device is disconnected and sub device is connected
                         // To copy data from sub device to main device
                         mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
-                        cachedDevice.switchMemberDeviceContent(device, cachedDevice);
+                        cachedDevice.switchMemberDeviceContent(device);
                         cachedDevice.refresh();
                         // It is necessary to do remove and add for updating the mapping on
                         // preference and device
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/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index a491455..e22f3f0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -113,12 +113,13 @@
 
             // Check current list of CachedDevices to see if any are Hearing Aid devices.
             mDeviceManager.updateHearingAidsDevices();
-            mIsProfileReady=true;
+            mIsProfileReady = true;
             mProfileManager.callServiceConnectedListeners();
         }
 
         public void onServiceDisconnected(int profile) {
-            mIsProfileReady=false;
+            mIsProfileReady = false;
+            mProfileManager.callServiceDisconnectedListeners();
         }
     }
 
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/bluetooth/OWNERS b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
index 387bae1..5e66972 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OWNERS
@@ -3,5 +3,7 @@
 [email protected]
 [email protected]
 [email protected]
[email protected]
[email protected]
 
 # Emergency approvers in case the above are not available
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
index b416738..39b4b8e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java
@@ -78,6 +78,9 @@
      * Config the MobileStatusTracker to start or stop monitoring platform signals.
      */
     public void setListening(boolean listening) {
+        if (mListening == listening) {
+            return;
+        }
         mListening = listening;
         if (listening) {
             mPhone.registerTelephonyCallback(mReceiverHandler::post, mTelephonyCallback);
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/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index bb6b293..a252f52 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -20,6 +20,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothA2dp;
@@ -78,6 +79,21 @@
                 .thenReturn(Arrays.asList(mDevice));
     }
 
+
+    @Test
+    public void onServiceConnected_isProfileReady() {
+        assertThat(mProfile.isProfileReady()).isTrue();
+        verify(mProfileManager).callServiceConnectedListeners();
+    }
+
+    @Test
+    public void onServiceDisconnected_profileNotReady() {
+        mServiceListener.onServiceDisconnected(BluetoothProfile.A2DP);
+
+        assertThat(mProfile.isProfileReady()).isFalse();
+        verify(mProfileManager).callServiceDisconnectedListeners();
+    }
+
     @Test
     public void supportsHighQualityAudio() {
         when(mBluetoothA2dp.isOptionalCodecsSupported(mDevice)).thenReturn(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index bef1d9c..62552f91 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
@@ -518,7 +519,8 @@
      */
     @Test
     public void onDeviceUnpaired_unpairCsipMainDevice() {
-        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
+        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         cachedDevice1.setGroupId(1);
@@ -527,7 +529,12 @@
 
         // Call onDeviceUnpaired for the one in mCachedDevices.
         mCachedDeviceManager.onDeviceUnpaired(cachedDevice1);
+
         verify(mDevice2).removeBond();
+        assertThat(cachedDevice1.getGroupId()).isEqualTo(
+                BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+        assertThat(cachedDevice2.getGroupId()).isEqualTo(
+                BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
     }
 
     /**
@@ -536,6 +543,7 @@
     @Test
     public void onDeviceUnpaired_unpairCsipSubDevice() {
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
         cachedDevice1.setGroupId(1);
@@ -544,7 +552,10 @@
 
         // Call onDeviceUnpaired for the one in mCachedDevices.
         mCachedDeviceManager.onDeviceUnpaired(cachedDevice2);
+
         verify(mDevice1).removeBond();
+        assertThat(cachedDevice2.getGroupId()).isEqualTo(
+                BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
     }
 
     /**
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 76c066c..79e9938 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -1050,4 +1050,23 @@
 
         assertThat(mCachedDevice.mDrawableCache.size()).isEqualTo(0);
     }
+
+    @Test
+    public void switchMemberDeviceContent_switchMainDevice_switchesSuccessful() {
+        mCachedDevice.mRssi = RSSI_1;
+        mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1;
+        mSubCachedDevice.mRssi = RSSI_2;
+        mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2;
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+
+        mCachedDevice.switchMemberDeviceContent(mSubCachedDevice);
+
+        assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2);
+        assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2);
+        assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice);
+        assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1);
+        assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
+        assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+    }
 }
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/HearingAidProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidProfileTest.java
index be3a517..101a6cd 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidProfileTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothAdapter;
@@ -66,7 +67,6 @@
 
         mProfile = new HearingAidProfile(context, mDeviceManager, mProfileManager);
         mServiceListener = mShadowBluetoothAdapter.getServiceListener();
-        mServiceListener.onServiceConnected(BluetoothProfile.HEADSET, mService);
     }
 
     @Test
@@ -74,4 +74,20 @@
         assertThat(mProfile.setActiveDevice(null)).isTrue();
         assertThat(mProfile.setActiveDevice(mBluetoothDevice)).isTrue();
     }
+
+    @Test
+    public void onServiceConnected_isProfileReady() {
+        mServiceListener.onServiceConnected(BluetoothProfile.HEARING_AID, mService);
+
+        assertThat(mProfile.isProfileReady()).isTrue();
+        verify(mProfileManager).callServiceConnectedListeners();
+    }
+
+    @Test
+    public void onServiceDisconnected_profileNotReady() {
+        mServiceListener.onServiceDisconnected(BluetoothProfile.HEARING_AID);
+
+        assertThat(mProfile.isProfileReady()).isFalse();
+        verify(mProfileManager).callServiceDisconnectedListeners();
+    }
 }
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/widget/AppHeaderPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppHeaderPreferenceTest.java
new file mode 100644
index 0000000..fd181ff
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/AppHeaderPreferenceTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.onBindViewHolder(mHolder);
+        mPreference.setSecondSummary(defaultTestText);
+
+        assertThat(((TextView) mRootView.findViewById(R.id.second_summary)).getText().toString())
+                .isEqualTo(defaultTestText);
+    }
+}
diff --git a/packages/SettingsProvider/res/values-ro/strings.xml b/packages/SettingsProvider/res/values-ro/strings.xml
index 561a213..db13019 100644
--- a/packages/SettingsProvider/res/values-ro/strings.xml
+++ b/packages/SettingsProvider/res/values-ro/strings.xml
@@ -21,5 +21,5 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4567566098528588863">"Stocare setări"</string>
     <string name="wifi_softap_config_change" msgid="5688373762357941645">"Setările hotspotului s-au modificat"</string>
-    <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Atingeți pentru detalii"</string>
+    <string name="wifi_softap_config_change_summary" msgid="8946397286141531087">"Atinge pentru detalii"</string>
 </resources>
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/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index ba7a9bc..e7c7ac0 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -31,7 +31,6 @@
 import android.provider.settings.backup.SystemSettings;
 
 import androidx.test.filters.SmallTest;
-import androidx.test.filters.Suppress;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Test;
@@ -709,7 +708,6 @@
                  Settings.Secure.DOCKED_CLOCK_FACE,
                  Settings.Secure.DOZE_PULSE_ON_LONG_PRESS,
                  Settings.Secure.EMERGENCY_ASSISTANCE_APPLICATION,
-                 Settings.Secure.ENABLED_ACCESSIBILITY_AUDIO_DESCRIPTION_BY_DEFAULT,
                  Settings.Secure.ENABLED_INPUT_METHODS,  // Intentionally removed in P
                  Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT,
                  Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
@@ -837,15 +835,64 @@
     }
 
     @Test
-    @Suppress //("b/148236308")
     public void secureSettingsBackedUpOrDenied() {
+        // List of settings that were not added to either SETTINGS_TO_BACKUP or
+        // BACKUP_DENY_LIST_SECURE_SETTINGS while this test was suppressed in
+        // the last two years. Settings in this list are temporarily allowed to
+        // not be explicitly listed as backed up or denied so we can re-enable
+        // this test.
+        //
+        // DO NOT ADD NEW SETTINGS TO THIS LIST!
+        Set<String> settingsNotBackedUpOrDeniedTemporaryAllowList =
+                newHashSet(
+                        Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING,
+                        Settings.Secure.AMBIENT_CONTEXT_CONSENT_COMPONENT,
+                        Settings.Secure.AMBIENT_CONTEXT_EVENT_ARRAY_EXTRA_KEY,
+                        Settings.Secure.AMBIENT_CONTEXT_PACKAGE_NAME_EXTRA_KEY,
+                        Settings.Secure.AUTO_REVOKE_DISABLED,
+                        Settings.Secure.BIOMETRIC_APP_ENABLED,
+                        Settings.Secure.BIOMETRIC_KEYGUARD_ENABLED,
+                        Settings.Secure.BIOMETRIC_VIRTUAL_ENABLED,
+                        Settings.Secure.BLUETOOTH_ADDR_VALID,
+                        Settings.Secure.BLUETOOTH_ADDRESS,
+                        Settings.Secure.BLUETOOTH_NAME,
+                        Settings.Secure.BUBBLE_IMPORTANT_CONVERSATIONS,
+                        Settings.Secure.CLIPBOARD_SHOW_ACCESS_NOTIFICATIONS,
+                        Settings.Secure.COMMUNAL_MODE_ENABLED,
+                        Settings.Secure.COMMUNAL_MODE_TRUSTED_NETWORKS,
+                        Settings.Secure.DEFAULT_VOICE_INPUT_METHOD,
+                        Settings.Secure.DOCK_SETUP_STATE,
+                        Settings.Secure.EXTRA_AUTOMATIC_POWER_SAVE_MODE,
+                        Settings.Secure.GAME_DASHBOARD_ALWAYS_ON,
+                        Settings.Secure.HDMI_CEC_SET_MENU_LANGUAGE_DENYLIST,
+                        Settings.Secure.LAUNCHER_TASKBAR_EDUCATION_SHOWING,
+                        Settings.Secure.LOCATION_COARSE_ACCURACY_M,
+                        Settings.Secure.LOCATION_SHOW_SYSTEM_OPS,
+                        Settings.Secure.NAS_SETTINGS_UPDATED,
+                        Settings.Secure.NAV_BAR_FORCE_VISIBLE,
+                        Settings.Secure.NAV_BAR_KIDS_MODE,
+                        Settings.Secure.NEARBY_FAST_PAIR_SETTINGS_DEVICES_COMPONENT,
+                        Settings.Secure.NEARBY_SHARING_SLICE_URI,
+                        Settings.Secure.NOTIFIED_NON_ACCESSIBILITY_CATEGORY_SERVICES,
+                        Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT,
+                        Settings.Secure.RELEASE_COMPRESS_BLOCKS_ON_INSTALL,
+                        Settings.Secure.SCREENSAVER_COMPLICATIONS_ENABLED,
+                        Settings.Secure.SHOW_QR_CODE_SCANNER_SETTING,
+                        Settings.Secure.SKIP_ACCESSIBILITY_SHORTCUT_DIALOG_TIMEOUT_RESTRICTION,
+                        Settings.Secure.SPATIAL_AUDIO_ENABLED,
+                        Settings.Secure.TIMEOUT_TO_USER_ZERO,
+                        Settings.Secure.UI_NIGHT_MODE_LAST_COMPUTED,
+                        Settings.Secure.UI_NIGHT_MODE_OVERRIDE_OFF,
+                        Settings.Secure.UI_NIGHT_MODE_OVERRIDE_ON);
+
         HashSet<String> keys = new HashSet<String>();
         Collections.addAll(keys, SecureSettings.SETTINGS_TO_BACKUP);
         Collections.addAll(keys, DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
-        checkSettingsBackedUpOrDenied(
-                getCandidateSettings(Settings.Secure.class),
-                keys,
-                BACKUP_DENY_LIST_SECURE_SETTINGS);
+
+        Set<String> allSettings = getCandidateSettings(Settings.Secure.class);
+        allSettings.removeAll(settingsNotBackedUpOrDeniedTemporaryAllowList);
+
+        checkSettingsBackedUpOrDenied(allSettings, keys, BACKUP_DENY_LIST_SECURE_SETTINGS);
     }
 
     private static void checkSettingsBackedUpOrDenied(
diff --git a/packages/Shell/res/values-nb/strings.xml b/packages/Shell/res/values-nb/strings.xml
index 625b15a..ce39385 100644
--- a/packages/Shell/res/values-nb/strings.xml
+++ b/packages/Shell/res/values-nb/strings.xml
@@ -18,8 +18,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Kommandoliste"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"Feilrapporter"</string>
-    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> blir generert"</string>
-    <string name="bugreport_finished_title" msgid="4429132808670114081">"Feilrapporten <xliff:g id="ID">#%d</xliff:g> er fullført"</string>
+    <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Feilrapport <xliff:g id="ID">#%d</xliff:g> blir generert"</string>
+    <string name="bugreport_finished_title" msgid="4429132808670114081">"Feilrapport <xliff:g id="ID">#%d</xliff:g> er fullført"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Legger til detaljer i feilrapporten"</string>
     <string name="bugreport_updating_wait" msgid="3322151947853929470">"Vent litt"</string>
     <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Feilrapporten vises snart på telefonen"</string>
@@ -38,7 +38,7 @@
     <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Skjermdump"</string>
     <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Skjermdumpen er tatt."</string>
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
-    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
+    <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapport <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
     <string name="bugreport_info_title" msgid="2306030793918239804">"Navn på feil"</string>
     <string name="bugreport_info_description" msgid="5072835127481627722">"Oppsummering av feil"</string>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index ba8079f..b7fb472 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -213,6 +213,7 @@
         "kotlinx-coroutines-android",
         "kotlinx-coroutines-core",
         "kotlinx_coroutines_test",
+        "kotlin-reflect",
         "iconloader_base",
         "SystemUI-tags",
         "SystemUI-proto",
@@ -244,11 +245,9 @@
     },
 }
 
-// Opt-in config for optimizing the SystemUI target using R8.
-// Enabled via `export SYSTEMUI_OPTIMIZE_JAVA=true`, or explicitly in Make via
-// the `SOONG_CONFIG_ANDROID_SYSTEMUI_OPTIMIZE_JAVA` variable.
-// TODO(b/203472868): Enable optimizations by default after stabilizing and
-// building out retrace infrastructure.
+// Opt-out config for optimizing the SystemUI target using R8.
+// Disabled via `export SYSTEMUI_OPTIMIZE_JAVA=false`, or explicitly in Make via
+// `SYSTEMUI_OPTIMIZE_JAVA := false`.
 soong_config_module_type {
     name: "systemui_optimized_java_defaults",
     module_type: "java_defaults",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 78dea89..2737ecf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -85,7 +85,6 @@
     <uses-permission android:name="android.permission.CONTROL_VPN" />
     <uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
     <uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"/>
-    <uses-permission android:name="android.permission.NETWORK_STACK"/>
     <!-- Physical hardware -->
     <uses-permission android:name="android.permission.MANAGE_USB" />
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
@@ -95,6 +94,7 @@
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.MANAGE_SENSOR_PRIVACY" />
     <uses-permission android:name="android.permission.OBSERVE_SENSOR_PRIVACY" />
+    <uses-permission android:name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT" />
 
     <!-- ActivityManager -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
@@ -152,6 +152,9 @@
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
     <uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" />
 
+    <!-- For auto-grant the access to the Settings' slice preferences, e.g. volume slices. -->
+    <uses-permission android:name="android.permission.READ_SEARCH_INDEXABLES" />
+
     <!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
     <uses-permission android:name="android.permission.SET_WALLPAPER"/>
 
@@ -411,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" />
@@ -956,5 +959,13 @@
             </intent-filter>
         </receiver>
 
+        <receiver android:name=".volume.VolumePanelDialogReceiver"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.settings.panel.action.VOLUME" />
+                <action android:name="com.android.systemui.action.LAUNCH_VOLUME_PANEL_DIALOG" />
+                <action android:name="com.android.systemui.action.DISMISS_VOLUME_PANEL_DIALOG" />
+            </intent-filter>
+        </receiver>
     </application>
 </manifest>
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/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..02d76f4
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
@@ -0,0 +1,99 @@
+/*
+ * 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("user_$index"),
+                                            image =
+                                                checkNotNull(
+                                                    AppCompatResources.getDrawable(
+                                                        context,
+                                                        R.drawable.ic_avatar_guest_user
+                                                    )
+                                                ),
+                                            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
new file mode 100644
index 0000000..bfbccb8
--- /dev/null
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -0,0 +1,877 @@
++packages/SystemUI
+-packages/SystemUI/animation/src/com/android/systemui/animation/FontInterpolator.kt
+-packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+-packages/SystemUI/animation/src/com/android/systemui/animation/TextAnimator.kt
+-packages/SystemUI/animation/src/com/android/systemui/animation/TextInterpolator.kt
+-packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BindServiceViaContextDetector.kt
+-packages/SystemUI/checks/src/com/android/internal/systemui/lint/BroadcastSentViaContextDetector.kt
+-packages/SystemUI/checks/src/com/android/internal/systemui/lint/GetMainLooperViaContextDetector.kt
+-packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
+-packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt
+-packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+-packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt
+-packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt
+-packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt
+-packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
+-packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt
+-packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+-packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+-packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainerController.kt
+-packages/SystemUI/shared/src/com/android/systemui/flags/Flag.kt
+-packages/SystemUI/shared/src/com/android/systemui/flags/FlagListenable.kt
+-packages/SystemUI/shared/src/com/android/systemui/flags/FlagManager.kt
+-packages/SystemUI/shared/src/com/android/systemui/flags/FlagSerializer.kt
+-packages/SystemUI/shared/src/com/android/systemui/flags/FlagSettingsHelper.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimator.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionSamplingInstance.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/rotation/FloatingRotationButtonPositionCalculator.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerManager.kt
+-packages/SystemUI/shared/src/com/android/systemui/shared/system/smartspace/SmartspaceState.kt
+-packages/SystemUI/shared/src/com/android/systemui/unfold/system/ActivityManagerActivityTypeProvider.kt
+-packages/SystemUI/shared/src/com/android/systemui/unfold/system/DeviceStateManagerFoldProvider.kt
+-packages/SystemUI/shared/src/com/android/systemui/unfold/system/SystemUnfoldSharedModule.kt
+-packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+-packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
+-packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+-packages/SystemUI/src/com/android/keyguard/BouncerPanelExpansionCalculator.kt
+-packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+-packages/SystemUI/src/com/android/keyguard/KeyguardBiometricLockoutLogger.kt
+-packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+-packages/SystemUI/src/com/android/keyguard/KeyguardListenQueue.kt
+-packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+-packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherAnchor.kt
+-packages/SystemUI/src/com/android/keyguard/clock/ClockPalette.kt
+-packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+-packages/SystemUI/src/com/android/keyguard/mediator/ScreenOnCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/BootCompleteCache.kt
+-packages/SystemUI/src/com/android/systemui/BootCompleteCacheImpl.kt
+-packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
+-packages/SystemUI/src/com/android/systemui/ChooserSelector.kt
+-packages/SystemUI/src/com/android/systemui/DarkReceiverImpl.kt
+-packages/SystemUI/src/com/android/systemui/DisplayCutoutBaseView.kt
+-packages/SystemUI/src/com/android/systemui/DualToneHandler.kt
+-packages/SystemUI/src/com/android/systemui/FaceScanningOverlay.kt
+-packages/SystemUI/src/com/android/systemui/ScreenDecorHwcLayer.kt
+-packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactoryBase.kt
+-packages/SystemUI/src/com/android/systemui/SystemUIInitializerFactory.kt
+-packages/SystemUI/src/com/android/systemui/SystemUIInitializerImpl.kt
+-packages/SystemUI/src/com/android/systemui/assist/AssistLogger.kt
+-packages/SystemUI/src/com/android/systemui/assist/AssistantInvocationEvent.kt
+-packages/SystemUI/src/com/android/systemui/assist/AssistantSessionEvent.kt
+-packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AlternateUdfpsTouchProvider.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricIconController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationViewController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsBpViewController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDrawable.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpDrawable.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsFpmOtherViewController.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsHapticsSimulator.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/Utils.kt
+-packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcherStartable.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/BroadcastSender.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/PendingRemovalStore.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+-packages/SystemUI/src/com/android/systemui/broadcast/logging/BroadcastDispatcherLogger.kt
+-packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+-packages/SystemUI/src/com/android/systemui/camera/CameraIntents.kt
+-packages/SystemUI/src/com/android/systemui/camera/CameraIntentsWrapper.kt
+-packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
+-packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
+-packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLogger.kt
+-packages/SystemUI/src/com/android/systemui/controls/ControlsMetricsLoggerImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
+-packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
+-packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapper.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfiguration.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/ServiceWrapper.kt
+-packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
+-packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
+-packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsFeatureEnabled.kt
+-packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsAnimations.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
+-packages/SystemUI/src/com/android/systemui/controls/management/StructureAdapter.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/Behavior.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlWithState.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlsActivity.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiController.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/CornerDrawable.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ThumbnailBehavior.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+-packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
+-packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+-packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt
+-packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt
+-packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
+-packages/SystemUI/src/com/android/systemui/decor/DecorProviderFactory.kt
+-packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
+-packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
+-packages/SystemUI/src/com/android/systemui/decor/PrivacyDotDecorProviderFactory.kt
+-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderFactory.kt
+-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerDecorProviderImpl.kt
+-packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
+-packages/SystemUI/src/com/android/systemui/demomode/DemoModeAvailabilityTracker.kt
+-packages/SystemUI/src/com/android/systemui/demomode/DemoModeController.kt
+-packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+-packages/SystemUI/src/com/android/systemui/doze/util/BurnInHelper.kt
+-packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
+-packages/SystemUI/src/com/android/systemui/dump/DumpHandler.kt
+-packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+-packages/SystemUI/src/com/android/systemui/dump/DumpsysTableLogger.kt
+-packages/SystemUI/src/com/android/systemui/dump/LogBufferEulogizer.kt
+-packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
+-packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
+-packages/SystemUI/src/com/android/systemui/flags/ServerFlagReader.kt
+-packages/SystemUI/src/com/android/systemui/flags/SystemPropertiesHelper.kt
+-packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+-packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+-packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+-packages/SystemUI/src/com/android/systemui/log/LogLevel.kt
+-packages/SystemUI/src/com/android/systemui/log/LogMessage.kt
+-packages/SystemUI/src/com/android/systemui/log/LogMessageImpl.kt
+-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt
+-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
+-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
+-packages/SystemUI/src/com/android/systemui/media/AnimationBindHandler.kt
+-packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
+-packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt
+-packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
+-packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+-packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt
+-packages/SystemUI/src/com/android/systemui/media/LocalMediaManagerFactory.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaFeatureFlag.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaHostStatesManager.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+-packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/MetadataAnimationHandler.kt
+-packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
+-packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+-packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+-packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
+-packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
+-packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
+-packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
+-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
+-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
+-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionCli.kt
+-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManager.kt
+-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerFactory.kt
+-packages/SystemUI/src/com/android/systemui/media/muteawait/MediaMuteAwaitLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesLogger.kt
+-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/MediaTttLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttReceiverLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderLogger.kt
+-packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLogger.kt
+-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt
+-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt
+-packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt
+-packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
+-packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt
+-packages/SystemUI/src/com/android/systemui/privacy/MediaProjectionPrivacyItemMonitor.kt
+-packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipBuilder.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyChipEvent.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyConfig.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialog.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogController.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogEvent.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+-packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+-packages/SystemUI/src/com/android/systemui/privacy/logging/PrivacyLogger.kt
+-packages/SystemUI/src/com/android/systemui/qs/AutoAddTracker.kt
+-packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+-packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+-packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
+-packages/SystemUI/src/com/android/systemui/qs/HeaderPrivacyIconsController.kt
+-packages/SystemUI/src/com/android/systemui/qs/QSEvents.kt
+-packages/SystemUI/src/com/android/systemui/qs/QSExpansionPathInterpolator.kt
+-packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
+-packages/SystemUI/src/com/android/systemui/qs/QSSquishinessController.kt
+-packages/SystemUI/src/com/android/systemui/qs/QSUtils.kt
+-packages/SystemUI/src/com/android/systemui/qs/SideLabelTileLayout.kt
+-packages/SystemUI/src/com/android/systemui/qs/VisibilityChangedDispatcher.kt
+-packages/SystemUI/src/com/android/systemui/qs/carrier/CellSignalState.kt
+-packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.kt
+-packages/SystemUI/src/com/android/systemui/qs/external/CustomTileStatePersister.kt
+-packages/SystemUI/src/com/android/systemui/qs/external/QSExternalModule.kt
+-packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialog.kt
+-packages/SystemUI/src/com/android/systemui/qs/external/TileRequestDialogEventLogger.kt
+-packages/SystemUI/src/com/android/systemui/qs/external/TileServiceRequestController.kt
+-packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+-packages/SystemUI/src/com/android/systemui/qs/tileimpl/HeightOverrideable.kt
+-packages/SystemUI/src/com/android/systemui/qs/tileimpl/IgnorableChildLinearLayout.kt
+-packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+-packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+-packages/SystemUI/src/com/android/systemui/qs/tiles/DeviceControlsTile.kt
+-packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+-packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
+-packages/SystemUI/src/com/android/systemui/ripple/RippleShader.kt
+-packages/SystemUI/src/com/android/systemui/ripple/RippleShaderUtilLibrary.kt
+-packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
+-packages/SystemUI/src/com/android/systemui/ripple/SdfShaderLibrary.kt
+-packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+-packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
+-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
+-packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotProxyService.kt
+-packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseDialog.kt
+-packages/SystemUI/src/com/android/systemui/sensorprivacy/SensorUseStartedActivity.kt
+-packages/SystemUI/src/com/android/systemui/settings/UserContentResolverProvider.kt
+-packages/SystemUI/src/com/android/systemui/settings/UserContextProvider.kt
+-packages/SystemUI/src/com/android/systemui/settings/UserFileManager.kt
+-packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
+-packages/SystemUI/src/com/android/systemui/settings/UserTracker.kt
+-packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+-packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessMirrorHandler.kt
+-packages/SystemUI/src/com/android/systemui/settings/brightness/MirroredBrightnessController.kt
+-packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManager.kt
+-packages/SystemUI/src/com/android/systemui/shade/CombinedShadeHeadersConstraintManagerImpl.kt
+-packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+-packages/SystemUI/src/com/android/systemui/shade/NPVCDownEventState.kt
+-packages/SystemUI/src/com/android/systemui/shade/NotifPanelEvents.kt
+-packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
+-packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt
+-packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+-packages/SystemUI/src/com/android/systemui/shade/ShadeLogger.kt
+-packages/SystemUI/src/com/android/systemui/shade/transition/ScrimShadeTransitionController.kt
+-packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
+-packages/SystemUI/src/com/android/systemui/shade/transition/SplitShadeOverScroller.kt
+-packages/SystemUI/src/com/android/systemui/smartspace/SmartspacePrecondition.kt
+-packages/SystemUI/src/com/android/systemui/smartspace/SmartspaceTargetFilter.kt
+-packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
+-packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceViewComponent.kt
+-packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenAndDreamTargetFilter.kt
+-packages/SystemUI/src/com/android/systemui/smartspace/preconditions/LockscreenPrecondition.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/AbstractLockscreenShadeTransitionController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/ActionClickLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/LockScreenShadeOverScroller.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeKeyguardTransitionController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeScrimTransitionController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/MediaArtworkProcessor.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/NotificationClickNotifier.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScroller.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScroller.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/commandline/CommandRegistry.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/AccessPointController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ConnectivityState.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileSignalControllerFactory.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileState.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/MobileStatusTrackerFactory.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/SignalCallback.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiState.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/connectivity/WifiStatusTrackerFactory.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/dagger/StartCentralSurfacesModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/StatusEvent.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/events/SystemStatusAnimationScheduler.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/gesture/GenericGestureDetector.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureHandler.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/gesture/SwipeStatusBarAwayGestureLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/gesture/TapGestureDetector.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/FeedbackIcon.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/LaunchAnimationParameters.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClickerLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListAttachState.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographer.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/PipelineDumper.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SuppressedAttachState.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolver.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DebugModeCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/dagger/CoordinatorsModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/BindEventManagerImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifStabilityManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTracker.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifEvent.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/DebugModeFilterProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/NotificationVisibilityProviderImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionHeaderVisibilityProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SectionStyleProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/MediaContainerController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGroupController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewListener.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifGutsViewManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifRowController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifShadeEventSource.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotificationVisibilityProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderExtensions.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/SectionHeaderController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDiffer.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewDifferLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationSectionHeadersModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconBuilder.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinderLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/people/ViewPipeline.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifBindPipelineLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowContentBindStageLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/RemoteInputViewModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationPriorityBucket.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/LSShadeTransitionLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/ScreenOffAnimationController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLaunchAnimatorController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocationPublisher.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemBarAttributesListener.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarIconBlocklist.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/StatusBarSystemEventAnimator.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometer.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallFlags.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManager.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/panelstate/PanelStateListener.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserInfoTracker.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherContainer.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherFeatureController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ConnectivityInfoProcessor.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManagerLogger.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyState.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplyViewHolder.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyStateInflater.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateView.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/VariableDateViewController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/WalletController.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/WalletControllerImpl.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/RemoteInput.kt
+-packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt
+-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
+-packages/SystemUI/src/com/android/systemui/unfold/FoldStateLogger.kt
+-packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt
+-packages/SystemUI/src/com/android/systemui/unfold/UnfoldLatencyTracker.kt
+-packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+-packages/SystemUI/src/com/android/systemui/unfold/UnfoldProgressProvider.kt
+-packages/SystemUI/src/com/android/systemui/user/UserCreator.kt
+-packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+-packages/SystemUI/src/com/android/systemui/user/UserSwitcherPopupMenu.kt
+-packages/SystemUI/src/com/android/systemui/user/UserSwitcherRootView.kt
+-packages/SystemUI/src/com/android/systemui/util/AsyncActivityLauncher.kt
+-packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt
+-packages/SystemUI/src/com/android/systemui/util/ConvenienceExtensions.kt
+-packages/SystemUI/src/com/android/systemui/util/DelayableMarqueeTextView.kt
+-packages/SystemUI/src/com/android/systemui/util/DumpUtils.kt
+-packages/SystemUI/src/com/android/systemui/util/InitializationChecker.kt
+-packages/SystemUI/src/com/android/systemui/util/LargeScreenUtils.kt
+-packages/SystemUI/src/com/android/systemui/util/ListenerSet.kt
+-packages/SystemUI/src/com/android/systemui/util/NeverExactlyLinearLayout.kt
+-packages/SystemUI/src/com/android/systemui/util/NoRemeasureMotionLayout.kt
+-packages/SystemUI/src/com/android/systemui/util/PluralMessageFormater.kt
+-packages/SystemUI/src/com/android/systemui/util/RingerModeTracker.kt
+-packages/SystemUI/src/com/android/systemui/util/RingerModeTrackerImpl.kt
+-packages/SystemUI/src/com/android/systemui/util/RoundedCornerProgressDrawable.kt
+-packages/SystemUI/src/com/android/systemui/util/SafeMarqueeTextView.kt
+-packages/SystemUI/src/com/android/systemui/util/SparseArrayUtils.kt
+-packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
+-packages/SystemUI/src/com/android/systemui/util/UserAwareController.kt
+-packages/SystemUI/src/com/android/systemui/util/WallpaperController.kt
+-packages/SystemUI/src/com/android/systemui/util/animation/AnimationUtil.kt
+-packages/SystemUI/src/com/android/systemui/util/animation/MeasurementInput.kt
+-packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayout.kt
+-packages/SystemUI/src/com/android/systemui/util/animation/TransitionLayoutController.kt
+-packages/SystemUI/src/com/android/systemui/util/animation/UniqueObjectHostView.kt
+-packages/SystemUI/src/com/android/systemui/util/collection/RingBuffer.kt
+-packages/SystemUI/src/com/android/systemui/util/concurrency/Execution.kt
+-packages/SystemUI/src/com/android/systemui/util/concurrency/PendingTasksContainer.kt
+-packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
+-packages/SystemUI/src/com/android/systemui/util/kotlin/CoroutinesModule.kt
+-packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+-packages/SystemUI/src/com/android/systemui/util/kotlin/IpcSerializer.kt
+-packages/SystemUI/src/com/android/systemui/util/kotlin/nullability.kt
+-packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
+-packages/SystemUI/src/com/android/systemui/util/wrapper/RotationPolicyWrapper.kt
+-packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt
+-packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
+-packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/BouncerPanelExpansionCalculatorTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/KeyguardBiometricLockoutLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/KeyguardUserSwitcherAnchorTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/clock/ClockPaletteTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/clock/ViewPreviewerTest.kt
+-packages/SystemUI/tests/src/com/android/keyguard/mediator/ScreenOnCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/BootCompleteCacheTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/DisplayCutoutBaseViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/InstanceIdSequenceFake.kt
+-packages/SystemUI/tests/src/com/android/systemui/ScreenDecorHwcLayerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/animation/FontInterpolatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewLaunchAnimatorControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/animation/TextAnimatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/animation/TextInterpolatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/battery/BatteryMeterViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/broadcast/ActionReceiverTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastSenderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/broadcast/PendingRemovalStoreTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/camera/CameraGestureHelperTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/camera/CameraIntentsTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/AuxiliaryPersistenceWrapperTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapperTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsTileResourceConfigurationImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/DeletionJobServiceTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/ServiceWrapperTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/AppAdapterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestDialogTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/management/TestControlsRequestDialog.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/ui/ControlViewHolderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/controls/ui/DetailDialogTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/decor/OverlayWindowTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/decor/PrivacyDotDecorProviderFactoryTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerDecorProviderFactoryTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/dump/DumpHandlerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/dump/DumpsysTableLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferHelper.kt
+-packages/SystemUI/tests/src/com/android/systemui/dump/LogEulogizerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/flags/FlagManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt
+-packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/AnimationBindHandlerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/MetadataAnimationHandlerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/SmartspaceMediaDataTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
+-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/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
+-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttSenderUiEventLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/FloatingRotationButtonPositionCalculatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyChipBuilderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyConfigFlagsTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/HeaderPrivacyIconsControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QSContainerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelSwitchToParentTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QSSquishinessControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/SettingObserverTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/carrier/CellSignalStateTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileStatePersisterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogEventLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/external/TileRequestDialogTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceRequestControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSFactoryImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/ResourceIconTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/TilesStatesTextTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AlarmTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BatterySaverTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CameraToggleTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DeviceControlsTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/DndTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/LocationTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/MicrophoneToggleTileTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/ripple/RippleViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/screenrecord/ScreenRecordDialogTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageCaptureImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessSliderControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/NotificationQSContainerControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/transition/ScrimShadeTransitionControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shade/transition/SplitShadeOverScrollerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldMoveFromCenterAnimatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/regionsampling/RegionSamplingInstanceTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/rotation/RotationButtonControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/shared/system/UncaughtExceptionPreHandlerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/smartspace/DreamSmartspaceControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/smartspace/LockscreenPreconditionTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/BlurUtilsTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/LSShadeTransitionLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/LightRevealScrimTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/MediaArtworkProcessorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/SingleShadeLockScreenOverScrollerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/SplitShadeLockScreenOverScrollerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateEventTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/VibratorHelperTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/CommandRegistryTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/AccessPointControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/gesture/GenericGestureDetectorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationLaunchAnimatorControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifLiveDataStoreImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifPipelineChoreographerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/TargetSdkResolverTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GroupCountCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SensitiveContentCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ShadeEventCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ViewConfigCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionInconsistencyTrackerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/provider/VisualStabilityProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/IconManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/MediaContainerViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/FoldStateListenerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxAppearanceCalculatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LetterboxBackgroundProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconContainerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarMoveFromCenterAnimationControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemBarAttributesListenerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallChronometerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/panelstate/PanelExpansionStateManagerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ClockTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceControlsControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/FlashlightControllerImplTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherAdapterTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SafetyControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+-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
+-packages/SystemUI/tests/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfigTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/unfold/util/FoldableTestUtils.kt
+-packages/SystemUI/tests/src/com/android/systemui/unfold/util/NaturalRotationUnfoldProgressProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/unfold/util/ScaleAwareUnfoldProgressProviderTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/unfold/util/TestFoldStateProvider.kt
+-packages/SystemUI/tests/src/com/android/systemui/usb/UsbPermissionActivityTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/user/UserCreatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/FakeSharedPreferencesTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/FloatingContentCoordinatorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/ListenerSetTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/RingerModeLiveDataTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/WallpaperControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/animation/AnimationUtilTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/collection/RingBufferTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/kotlin/IpcSerializerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
+-packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+-packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+-packages/SystemUI/tests/utils/src/com/android/systemui/util/FakeSharedPreferences.kt
+-packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/ScreenSizeFoldProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/compat/SizeScreenStatusProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldBackground.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/dagger/UnfoldMain.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/screen/ScreenStatusProvider.kt
+-packages/SystemUI/unfold/src/com/android/systemui/unfold/util/ScaleAwareTransitionProgressProvider.kt
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 1ac1e3a..01e5d86 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -17,7 +17,6 @@
 import android.graphics.drawable.Drawable
 import android.view.View
 import com.android.systemui.plugins.annotations.ProvidesInterface
-import com.android.systemui.shared.regionsampling.RegionDarkness
 import java.io.PrintWriter
 import java.util.Locale
 import java.util.TimeZone
@@ -62,7 +61,7 @@
 
     /** Initializes various rendering parameters. If never called, provides reasonable defaults. */
     fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
-        events.onColorPaletteChanged(resources, RegionDarkness.DEFAULT, RegionDarkness.DEFAULT)
+        events.onColorPaletteChanged(resources, true, true)
         animations.doze(dozeFraction)
         animations.fold(foldFraction)
         events.onTimeTick()
@@ -92,8 +91,8 @@
     /** Call whenever the color palette should update */
     fun onColorPaletteChanged(
             resources: Resources,
-            smallClockIsDark: RegionDarkness,
-            largeClockIsDark: RegionDarkness
+            smallClockIsDark: Boolean,
+            largeClockIsDark: Boolean
     ) { }
 }
 
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/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_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 8b8ebf0..3ad7c8c 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -23,6 +23,7 @@
     android:id="@+id/keyguard_clock_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:clipChildren="false"
     android:layout_gravity="center_horizontal|top">
     <FrameLayout
         android:id="@+id/lockscreen_clock_view"
@@ -30,16 +31,13 @@
         android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:paddingStart="@dimen/clock_padding_start">
-    </FrameLayout>
+        android:paddingStart="@dimen/clock_padding_start" />
     <FrameLayout
         android:id="@+id/lockscreen_clock_view_large"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_below="@id/keyguard_slice_view"
-        android:paddingTop="@dimen/keyguard_large_clock_top_padding"
-        android:visibility="gone">
-    </FrameLayout>
+        android:layout_marginTop="@dimen/keyguard_large_clock_top_margin"
+        android:visibility="gone" />
 
     <!-- Not quite optimal but needed to translate these items as a group. The
          NotificationIconContainer has its own logic for translation. -->
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..f2fe520 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"
@@ -52,14 +49,12 @@
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="@dimen/eca_overlap" />
-
         <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 +190,6 @@
                     />
         </LinearLayout>
     </LinearLayout>
-
     <include layout="@layout/keyguard_eca"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
@@ -205,5 +199,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..a21ec29 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"
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 86546ed..be52c44 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ልክ ያልሆነ ካርድ።"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"ባትሪ ሞልቷል"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በገመድ አልባ ኃይል በመሙላት ላይ"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ኃይል በመሙላት ላይ"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ኃይል በመሙላት ላይ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በፍጥነት ኃይልን በመሙላት ላይ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • በዝግታ ኃይልን በመሙላት ላይ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ባትሪን ለመጠበቅ ኃይል መሙላት ባለበት ቆሟል"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ለመክፈት ምናሌ ተጫን።"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"አውታረ መረብ ተቆልፏል"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ምንም ሲም ካርድ የለም"</string>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index 06da1bf..b22655a 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"চ্চার্জ কৰা হ’ল"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • বেতাঁৰৰ জৰিয়তে চাৰ্জ কৰি থকা হৈছে"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • চ্চার্জ কৰি থকা হৈছে"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • দ্ৰুত গতিৰে চ্চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • লাহে লাহে চ্চাৰ্জ কৰি থকা হৈছে"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • বেটাৰী সুৰক্ষিত কৰিবলৈ চাৰ্জিং পজ কৰা হৈছে"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"আনলক কৰিবলৈ মেনু টিপক।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"নেটৱর্ক লক কৰা অৱস্থাত আছে"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"কোনো ছিম কাৰ্ড নাই"</string>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index d508d09..616d31a 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Несапраўдная картка."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Зараджаны"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе бесправадная зарадка"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе зарадка"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе зарадка"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе хуткая зарадка"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ідзе павольная зарадка"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарадка прыпынена дзеля ашчады акумулятара"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Націсніце кнопку \"Меню\", каб разблакіраваць."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сетка заблакіравана"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Няма SIM-карты"</string>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 68db723..331c355 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ugyldigt kort."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Opladet"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Trådløs opladning"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader hurtigt"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Oplader langsomt"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Opladningen er sat på pause for at beskytte batteriet"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Tryk på menuen for at låse op."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netværket er låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Intet SIM-kort"</string>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index 05c5e92..c19b357 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ungültige Karte."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Aufgeladen"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kabelloses Laden"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird geladen"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird geladen"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird schnell geladen"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wird langsam geladen"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladevorgang angehalten, um den Akku zu schonen"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Zum Entsperren die Menütaste drücken."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Netzwerk gesperrt"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Keine SIM-Karte"</string>
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-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index 94437b3..dceb78e 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kehtetu kaart."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Laetud"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Juhtmeta laadimine"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laadimine"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laadimine"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kiirlaadimine"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Aeglane laadimine"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laadimine on peatatud, et akut kaitsta"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Vajutage avamiseks menüüklahvi."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Võrk on lukus"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM-kaarti pole"</string>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index c63cb1a..f8cec42 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Virheellinen kortti"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Ladattu"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan langattomasti"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan nopeasti"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ladataan hitaasti"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Lataus on keskeytetty akun suojaamiseksi"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Poista lukitus painamalla Valikkoa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Verkko lukittu"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ei SIM-korttia"</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 bab0af6..62379f8 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Carte non valide."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Chargé"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • En charge sans fil"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge…"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge rapide…"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge lente…"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • La recharge est en pause pour protéger la batterie"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Appuyez sur \"Menu\" pour déverrouiller le clavier."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Réseau verrouillé"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Pas de carte SIM"</string>
@@ -55,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>
@@ -70,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>
@@ -87,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-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index a579acb..4fbdd67 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"A tarxeta non é válida."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Cargado"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando sen fíos"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando rapidamente"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Cargando lentamente"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • A carga púxose en pausa para protexer a batería"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Preme Menú para desbloquear."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Bloqueada pola rede"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Sen tarxeta SIM"</string>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index c3ba5b7..3412026 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Սխալ քարտ"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Լիցքավորված է"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Անլար լիցքավորում"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորում"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորում"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Արագ լիցքավորում"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Դանդաղ լիցքավորում"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Լիցքավորումը դադարեցվել է՝ մարտկոցը պաշտպանելու համար"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ապակողպելու համար սեղմեք Ընտրացանկը:"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ցանցը կողպված է"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM քարտ չկա"</string>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 4b27503..6abdc82 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ógilt kort."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Fullhlaðin"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í þráðlausri hleðslu"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í hleðslu"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Í hleðslu"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hröð hleðsla"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hæg hleðsla"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Gert var hlé á hleðslu til að vernda rafhlöðuna"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ýttu á valmyndarhnappinn til að taka úr lás."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Net læst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ekkert SIM-kort"</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-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 8c81ebe..d6d5bcd 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Жарамсыз карта."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Зарядталды"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Сымсыз зарядталуда"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядталып жатыр."</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядталуда"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Жылдам зарядталуда"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Баяу зарядталуда"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Батареяны қорғау мақсатында зарядтау кідіртілді."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Ашу үшін \"Мәзір\" пернесін басыңыз."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Желі құлыптаулы"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM картасы салынбаған"</string>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 34b2181..00bfe05 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"បណ្ណមិនត្រឹមត្រូវទេ។"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"បាន​សាក​ថ្មពេញ"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុងសាកថ្ម​ឥតខ្សែ"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្ម"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្ម"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • កំពុង​សាកថ្មយឺត"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ការសាក​ថ្ម​ត្រូវ​បាន​ផ្អាក ដើម្បី​ការពារ​ថ្ម"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ចុចម៉ឺនុយ ​ដើម្បី​ដោះ​សោ។"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"បណ្ដាញ​ជាប់​សោ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"គ្មាន​ស៊ីម​កាត​ទេ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index 4d1f9a0..d371a4b 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nederīga karte."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Akumulators uzlādēts"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek bezvadu uzlāde"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek uzlāde"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek uzlāde"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek ātrā uzlāde"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Notiek lēnā uzlāde"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Uzlāde ir pārtraukta, lai aizsargātu akumulatoru"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lai atbloķētu, nospiediet izvēlnes ikonu."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Tīkls ir bloķēts."</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nav SIM kartes."</string>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 45a4dfb1..ef22564 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Неважечка картичка."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Полна"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Се полни безжично"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Се полни"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Се полни"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Брзо полнење"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Бавно полнење"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Полнењето е паузирано за да се заштити батеријата"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Притиснете „Мени“ за отклучување."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мрежата е заклучена"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нема SIM-картичка"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index dcaee63..409f727 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"ਅਵੈਧ ਕਾਰਡ।"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"ਚਾਰਜ ਹੋ ਗਿਆ"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬਿਨਾਂ ਤਾਰ ਤੋਂ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ਬੈਟਰੀ ਦੀ ਸੁਰੱਖਿਆ ਲਈ ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"ਅਣਲਾਕ ਕਰਨ ਲਈ \"ਮੀਨੂ\" ਦਬਾਓ।"</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ਨੈੱਟਵਰਕ  ਲਾਕ  ਕੀਤਾ ਗਿਆ"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"ਕੋਈ ਸਿਮ ਕਾਰਡ ਨਹੀਂ"</string>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index aa659a8..52bc982 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Nieprawidłowa karta."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Naładowana"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie bezprzewodowe"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Ładowanie"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Szybkie ładowanie"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wolne ładowanie"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Wstrzymano ładowanie, aby chronić baterię"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Naciśnij Menu, aby odblokować."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Sieć zablokowana"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Brak karty SIM"</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-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index d83328b..2b8f8d6 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ошибка SIM-карты."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Батарея заряжена"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Беспроводная зарядка"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Зарядка"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"Идет зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"Идет быстрая зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"Идет медленная зарядка (<xliff:g id="PERCENTAGE">%s</xliff:g>)"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Чтобы продлить срок службы батареи, зарядка приостановлена"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Для разблокировки нажмите \"Меню\"."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Сеть заблокирована"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Нет SIM-карты."</string>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 580acef..4e911de 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"වලංගු නොවන කාඩ්පත."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"අරෝපිතයි"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • නොරැහැන්ව ආරෝපණ කෙරේ"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණය වෙමින්"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • ආරෝපණය වෙමින්"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • වේගයෙන් ආරෝපණය වෙමින්"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • සෙමින් ආරෝපණය වෙමින්"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • බැටරිය ආරක්ෂා කිරීම සඳහා ආරෝපණය විරාම කර ඇත"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"අගුලු හැරීමට මෙනුව ඔබන්න."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"ජාලය අගුළු දමා ඇත"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM පත නැත"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 4001bff..772308f 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Neveljavna kartica"</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Baterija napolnjena"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • brezžično polnjenje"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Polnjenje"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • polnjenje"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • hitro polnjenje"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • počasno polnjenje"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Zaradi zaščite baterije je polnjenje začasno zaustavljeno"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Če želite odkleniti, pritisnite meni."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Omrežje je zaklenjeno"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Ni kartice SIM"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index b42def6..c758462 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Karta e pavlefshme."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"I karikuar"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me valë"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet me shpejtësi"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Po karikohet ngadalë"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Karikimi është vendosur në pauzë për të mbrojtur baterinë"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Shtyp \"Meny\" për të shkyçur."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Rrjeti është i kyçur"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Nuk ka kartë SIM"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 40abf95..fa241d9 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Ogiltigt kort."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Laddat"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas trådlöst"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas snabbt"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddas långsamt"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Laddningen har pausats för att skydda batteriet"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Lås upp genom att trycka på Meny."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Nätverk låst"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Inget SIM-kort"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 816b6aa..791bceb 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Kadi si Sahihi."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Betri imejaa"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji bila kutumia waya"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji kwa kasi"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Inachaji pole pole"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Imesitisha kuchaji ili kulinda betri"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Bonyeza Menyu ili kufungua."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mtandao umefungwa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Hakuna SIM kadi"</string>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 4e144a0..54aaae3 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Geçersiz Kart."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Şarj oldu"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Kablosuz olarak şarj ediliyor"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj oluyor"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj oluyor"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Hızlı şarj oluyor"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Yavaş şarj oluyor"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Şarj işlemi pili korumak için duraklatıldı"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Kilidi açmak için Menü\'ye basın."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Ağ kilitli"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"SIM kart yok"</string>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index d9730fa..6144c1c 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Недійсна картка."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Заряджено"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Бездротове заряджання"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Швидке заряджання"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Повільне заряджання"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Заряджання призупинено, щоб захистити акумулятор"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Натисніть меню, щоб розблокувати."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Мережу заблоковано"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Немає SIM-карти"</string>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 66badc8..1d6cfa8 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -26,13 +26,11 @@
     <string name="keyguard_sim_error_message_short" msgid="633630844240494070">"Thẻ không hợp lệ."</string>
     <string name="keyguard_charged" msgid="5478247181205188995">"Đã sạc đầy"</string>
     <string name="keyguard_plugged_in_wireless" msgid="2537874724955057383">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc không dây"</string>
-    <!-- no translation found for keyguard_plugged_in_dock (2122073051904360987) -->
-    <skip />
+    <string name="keyguard_plugged_in_dock" msgid="2122073051904360987">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc"</string>
     <string name="keyguard_plugged_in" msgid="8169926454348380863">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc"</string>
     <string name="keyguard_plugged_in_charging_fast" msgid="4386594091107340426">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc nhanh"</string>
     <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đang sạc chậm"</string>
-    <!-- no translation found for keyguard_plugged_in_charging_limited (1709413803451065875) -->
-    <skip />
+    <string name="keyguard_plugged_in_charging_limited" msgid="1709413803451065875">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Đã tạm dừng sạc để bảo vệ pin"</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8448804180089936954">"Nhấn vào Menu để mở khóa."</string>
     <string name="keyguard_network_locked_message" msgid="407096292844868608">"Mạng đã bị khóa"</string>
     <string name="keyguard_missing_sim_message_short" msgid="704159478161444907">"Không có thẻ SIM"</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 8fa2204..d90156d 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -217,7 +217,7 @@
      the force lock button. [CHAR LIMIT=80] -->
     <string name="kg_prompt_reason_user_request">Device was locked manually</string>
 
-    <!-- Face hint message when finger was not recognized. [CHAR LIMIT=20] -->
+    <!-- Face hint message when face was not recognized. [CHAR LIMIT=20] -->
     <string name="kg_face_not_recognized">Not recognized</string>
 
      <!-- Error message indicating that the camera privacy sensor has been turned on [CHAR LIMIT=53] -->
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_circular_unchecked.xml b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
index 9b43cf6..779ab81 100644
--- a/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
+++ b/packages/SystemUI/res/drawable/ic_circular_unchecked.xml
@@ -4,6 +4,6 @@
     android:viewportWidth="24"
     android:viewportHeight="24">
   <path
-      android:fillColor="@color/media_dialog_inactive_item_main_content"
+      android:fillColor="@color/media_dialog_item_main_content"
       android:pathData="M12,22q-2.075,0 -3.9,-0.788 -1.825,-0.787 -3.175,-2.137 -1.35,-1.35 -2.137,-3.175Q2,14.075 2,12t0.788,-3.9q0.787,-1.825 2.137,-3.175 1.35,-1.35 3.175,-2.137Q9.925,2 12,2t3.9,0.788q1.825,0.787 3.175,2.137 1.35,1.35 2.137,3.175Q22,9.925 22,12t-0.788,3.9q-0.787,1.825 -2.137,3.175 -1.35,1.35 -3.175,2.137Q14.075,22 12,22zM12,12zM12,20q3.325,0 5.663,-2.337Q20,15.325 20,12t-2.337,-5.662Q15.325,4 12,4T6.338,6.338Q4,8.675 4,12q0,3.325 2.338,5.663Q8.675,20 12,20z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_present_to_all.xml b/packages/SystemUI/res/drawable/ic_present_to_all.xml
new file mode 100644
index 0000000..d6c9bbe
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_present_to_all.xml
@@ -0,0 +1,25 @@
+ <!--
+  ~ 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.
+  -->
+ <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="M21,3L3,3c-1.11,0 -2,0.89 -2,2v14c0,1.11 0.89,2 2,2h18c1.11,0 2,-0.89 2,-2L23,5c0,-1.11 -0.89,-2 -2,-2zM21,19.02L3,19.02L3,4.98h18v14.04zM8,12l4,-4 4,4 -1.41,1.41L13,11.83L13,16h-2v-4.17l-1.59,1.59L8,12z"/>
+ </vector>
diff --git a/packages/SystemUI/res/drawable/media_output_status_failed.xml b/packages/SystemUI/res/drawable/media_output_status_failed.xml
index 05c6358..0599e23 100644
--- a/packages/SystemUI/res/drawable/media_output_status_failed.xml
+++ b/packages/SystemUI/res/drawable/media_output_status_failed.xml
@@ -21,6 +21,6 @@
         android:viewportHeight="24"
         android:tint="?attr/colorControlNormal">
     <path
-        android:fillColor="@color/media_dialog_inactive_item_main_content"
+        android:fillColor="@color/media_dialog_item_main_content"
         android:pathData="M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
 </vector>
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_media_entry_chip.xml b/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml
new file mode 100644
index 0000000..50f3ffc
--- /dev/null
+++ b/packages/SystemUI/res/layout/dream_overlay_media_entry_chip.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/media_entry_chip"
+    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/ic_music_note"
+    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/controls_media_title" />
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_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
new file mode 100644
index 0000000..4ad6849
--- /dev/null
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -0,0 +1,92 @@
+<?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.
+  -->
+<com.android.internal.widget.ResolverDrawerLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    androidprv:maxCollapsedHeight="0dp"
+    androidprv:maxCollapsedHeightSmall="56dp"
+    androidprv:maxWidth="@*android:dimen/chooser_width"
+    android:id="@*android:id/contentPanel">
+
+    <LinearLayout
+        android:id="@*android:id/chooser_header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        androidprv:layout_alwaysShow="true"
+        android:gravity="center"
+        android:elevation="0dp"
+        android:background="@*android:drawable/bottomsheet_background">
+
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="@dimen/media_projection_app_selector_icon_size"
+            android:layout_height="@dimen/media_projection_app_selector_icon_size"
+            android:layout_marginTop="@*android:dimen/chooser_edge_margin_normal"
+            android:layout_marginBottom="@*android:dimen/chooser_edge_margin_normal"
+            android:importantForAccessibility="no"
+            android:tint="?android:attr/textColorPrimary"/>
+
+        <TextView android:id="@*android:id/title"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:gravity="center"
+            android:paddingBottom="@*android:dimen/chooser_view_spacing"
+            android:paddingLeft="24dp"
+            android:paddingRight="24dp"/>
+    </LinearLayout>
+
+    <FrameLayout
+        android:id="@*android:id/content_preview_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone" />
+
+    <TabHost
+        android:id="@*android:id/profile_tabhost"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:background="?android:attr/colorBackground">
+        <LinearLayout
+            android:orientation="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <TabWidget
+                android:id="@*android:id/tabs"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone">
+            </TabWidget>
+            <FrameLayout
+                android:id="@*android:id/tabcontent"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+                <com.android.internal.app.ResolverViewPager
+                    android:id="@*android:id/profile_pager"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"/>
+            </FrameLayout>
+        </LinearLayout>
+    </TabHost>
+
+</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml
deleted file mode 100644
index ec00429..0000000
--- a/packages/SystemUI/res/layout/people_strip.xml
+++ /dev/null
@@ -1,102 +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.
-  -->
-
-<com.android.systemui.statusbar.notification.stack.PeopleHubView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_section_header_height"
-    android:paddingStart="4dp"
-    android:paddingEnd="4dp"
-    android:focusable="true"
-    android:clickable="true"
->
-
-    <LinearLayout
-        android:id="@+id/people_list"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginEnd="8dp"
-        android:gravity="bottom"
-        android:orientation="horizontal"
-        android:forceHasOverlappingRendering="false"
-        android:clipChildren="false">
-
-        <FrameLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="start|center_vertical"
-            android:layout_weight="1"
-            android:forceHasOverlappingRendering="false">
-
-            <TextView
-                android:id="@+id/header_label"
-                style="@style/TextAppearance.NotificationSectionHeaderButton"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/notification_section_header_conversations"
-            />
-
-        </FrameLayout>
-
-        <ImageView
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:padding="8dp"
-            android:scaleType="fitCenter"
-            android:forceHasOverlappingRendering="false"
-            android:visibility="gone"
-        />
-
-        <ImageView
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:padding="8dp"
-            android:scaleType="fitCenter"
-            android:forceHasOverlappingRendering="false"
-            android:visibility="gone"
-        />
-
-        <ImageView
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:padding="8dp"
-            android:scaleType="fitCenter"
-            android:forceHasOverlappingRendering="false"
-            android:visibility="gone"
-        />
-
-        <ImageView
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:padding="8dp"
-            android:scaleType="fitCenter"
-            android:forceHasOverlappingRendering="false"
-            android:visibility="gone"
-        />
-
-        <ImageView
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:padding="8dp"
-            android:scaleType="fitCenter"
-            android:forceHasOverlappingRendering="false"
-            android:visibility="gone"
-        />
-
-    </LinearLayout>
-
-</com.android.systemui.statusbar.notification.stack.PeopleHubView>
diff --git a/packages/SystemUI/res/layout/sidefps_view.xml b/packages/SystemUI/res/layout/sidefps_view.xml
index 921f788..73050c2 100644
--- a/packages/SystemUI/res/layout/sidefps_view.xml
+++ b/packages/SystemUI/res/layout/sidefps_view.xml
@@ -23,4 +23,4 @@
     app:lottie_autoPlay="true"
     app:lottie_loop="true"
     app:lottie_rawRes="@raw/sfps_pulse"
-    android:contentDescription="@string/accessibility_fingerprint_label"/>
+    android:importantForAccessibility="no"/>
\ No newline at end of file
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/layout/volume_panel_dialog.xml b/packages/SystemUI/res/layout/volume_panel_dialog.xml
new file mode 100644
index 0000000..99a1b5c
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_panel_dialog.xml
@@ -0,0 +1,101 @@
+<?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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/volume_panel_dialog"
+    android:layout_width="@dimen/large_dialog_width"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/Widget.SliceView.Panel"
+        android:gravity="center_vertical|center_horizontal"
+        android:layout_marginTop="@dimen/dialog_top_padding"
+        android:layout_marginBottom="@dimen/dialog_bottom_padding"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/volume_panel_dialog_title"
+            android:ellipsize="end"
+            android:gravity="center_vertical|center_horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/sound_settings"
+            android:textAppearance="@style/TextAppearance.Dialog.Title"/>
+    </LinearLayout>
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/volume_panel_parent_layout"
+        android:scrollbars="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:minHeight="304dp"
+        android:layout_weight="1"
+        android:overScrollMode="never"/>
+
+    <LinearLayout
+        android:id="@+id/button_layout"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/dialog_button_vertical_padding"
+        android:layout_marginStart="@dimen/dialog_side_padding"
+        android:layout_marginEnd="@dimen/dialog_side_padding"
+        android:layout_marginBottom="@dimen/dialog_bottom_padding"
+        android:baselineAligned="false"
+        android:clickable="false"
+        android:focusable="false">
+
+        <LinearLayout
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="start|center_vertical"
+            android:orientation="vertical">
+            <Button
+                android:id="@+id/settings_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/volume_panel_dialog_settings_button"
+                android:ellipsize="end"
+                android:maxLines="1"
+                style="@style/Widget.Dialog.Button.BorderButton"
+                android:clickable="true"
+                android:focusable="true"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/dialog_button_horizontal_padding"
+            android:layout_gravity="end|center_vertical">
+            <Button
+                android:id="@+id/done_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/inline_done_button"
+                style="@style/Widget.Dialog.Button"
+                android:maxLines="1"
+                android:ellipsize="end"
+                android:clickable="true"
+                android:focusable="true"/>
+        </LinearLayout>
+    </LinearLayout>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/volume_panel_slice_slider_row.xml b/packages/SystemUI/res/layout/volume_panel_slice_slider_row.xml
new file mode 100644
index 0000000..d1303ed
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_panel_slice_slider_row.xml
@@ -0,0 +1,31 @@
+<?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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/slice_slider_layout"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <androidx.slice.widget.SliceView
+        android:id="@+id/slice_view"
+        style="@style/Widget.SliceView.Panel.Slider"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingVertical="@dimen/volume_panel_slice_vertical_padding"
+        android:paddingHorizontal="@dimen/volume_panel_slice_horizontal_padding"/>
+</LinearLayout>
\ No newline at end of file
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..b6bfc1b3 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-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 54c5490..dc2bee5 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -66,10 +66,12 @@
 
     <!-- media output dialog-->
     <color name="media_dialog_background">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_active_item_main_content">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_inactive_item_main_content">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_item_status">@color/material_dynamic_neutral10</color>
-    <color name="media_dialog_item_background">@color/material_dynamic_secondary95</color>
+    <color name="media_dialog_item_main_content">@color/material_dynamic_primary90</color>
+    <color name="media_dialog_item_background">@color/material_dynamic_neutral_variant20</color>
+    <color name="media_dialog_connected_item_background">@color/material_dynamic_secondary20</color>
+    <color name="media_dialog_seekbar_progress">@color/material_dynamic_secondary40</color>
+    <color name="media_dialog_button_background">@color/material_dynamic_primary70</color>
+    <color name="media_dialog_solid_button_text">@color/material_dynamic_secondary20</color>
 
     <!-- Biometric dialog colors -->
     <color name="biometric_dialog_gray">#ffcccccc</color>
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/config.xml b/packages/SystemUI/res/values/config.xml
index ec22c60..a802723 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>
@@ -617,8 +614,9 @@
     <!-- 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 +627,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 e34d422..9cb4cc4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -479,6 +479,10 @@
 
     <dimen name="volume_tool_tip_arrow_corner_radius">2dp</dimen>
 
+    <!-- Volume panel slices dimensions -->
+    <dimen name="volume_panel_slice_vertical_padding">8dp</dimen>
+    <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen>
+
     <!-- Size of each item in the ringer selector drawer. -->
     <dimen name="volume_ringer_drawer_item_size">42dp</dimen>
     <dimen name="volume_ringer_drawer_item_size_half">21dp</dimen>
@@ -665,7 +669,7 @@
     <!-- When large clock is showing, offset the smartspace by this amount -->
     <dimen name="keyguard_smartspace_top_offset">12dp</dimen>
     <!-- With the large clock, move up slightly from the center -->
-    <dimen name="keyguard_large_clock_top_padding">100dp</dimen>
+    <dimen name="keyguard_large_clock_top_margin">-60dp</dimen>
 
     <dimen name="notification_scrim_corner_radius">32dp</dimen>
 
@@ -1219,6 +1223,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>
@@ -1449,6 +1464,8 @@
 
     <dimen name="fgs_manager_list_top_spacing">12dp</dimen>
 
+    <dimen name="media_projection_app_selector_icon_size">32dp</dimen>
+
     <!-- Dream overlay related dimensions -->
     <dimen name="dream_overlay_status_bar_height">60dp</dimen>
     <dimen name="dream_overlay_status_bar_margin">40dp</dimen>
@@ -1471,14 +1488,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/ids.xml b/packages/SystemUI/res/values/ids.xml
index dca5ea8..8084254 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -131,7 +131,11 @@
     <!-- For StatusIconContainer to tag its icon views -->
     <item type="id" name="status_bar_view_state_tag" />
 
+    <!-- Default display cutout on the physical top of screen -->
     <item type="id" name="display_cutout" />
+    <item type="id" name="display_cutout_left" />
+    <item type="id" name="display_cutout_right" />
+    <item type="id" name="display_cutout_bottom" />
 
     <item type="id" name="row_tag_for_content_view" />
 
@@ -179,5 +183,7 @@
 
     <!-- face scanning view id -->
     <item type="id" name="face_scanning_anim"/>
+
+    <item type="id" name="qqs_tile_layout"/>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index bfdb170..9324e8f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -389,6 +389,10 @@
     <string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string>
     <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
     <string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string>
+    <!-- Message shown to inform the user a face cannot be recognized. [CHAR LIMIT=25] -->
+    <string name="keyguard_face_failed">Can\u2019t recognize face</string>
+    <!-- Message shown to suggest using fingerprint sensor to authenticate after another biometric failed. [CHAR LIMIT=25] -->
+    <string name="keyguard_suggest_fingerprint">Use fingerprint instead</string>
 
     <!-- Content description of the bluetooth icon when connected for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_bluetooth_connected">Bluetooth connected.</string>
@@ -1139,6 +1143,11 @@
     <!-- Content description for accessibility: Hint if click will disable. [CHAR LIMIT=NONE] -->
     <string name="volume_odi_captions_hint_disable">disable</string>
 
+    <!-- Sound and vibration settings dialog title. [CHAR LIMIT=30] -->
+    <string name="sound_settings">Sound &amp; vibration</string>
+    <!-- Label for button to go to sound settings screen [CHAR_LIMIT=30] -->
+    <string name="volume_panel_dialog_settings_button">Settings</string>
+
     <!-- content description for audio output chooser [CHAR LIMIT=NONE]-->
 
     <!-- Screen pinning dialog title. -->
@@ -1635,8 +1644,9 @@
     <!-- The tile in quick settings is unavailable. [CHAR LIMIT=32] -->
     <string name="tile_unavailable">Unavailable</string>
 
-    <!-- The tile in quick settings is disabled by a device administration policy [CHAR LIMIT=32] -->
-    <string name="tile_disabled">Disabled</string>
+    <!-- Accessibility text for the click action on a tile that is disabled by policy. This will
+         be used following "Double-tap to..." [CHAR LIMIT=NONE] -->
+    <string name="accessibility_tile_disabled_by_policy_action_description">learn more</string>
 
     <!-- SysUI Tuner: Button that leads to the navigation bar customization screen [CHAR LIMIT=60] -->
     <string name="nav_bar">Navigation bar</string>
@@ -1852,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 f7acf06..a734fa7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -477,7 +477,7 @@
 
     <style name="MediaOutputItemInactiveTitle">
         <item name="android:textSize">16sp</item>
-        <item name="android:textColor">@color/media_dialog_inactive_item_main_content</item>
+        <item name="android:textColor">@color/media_dialog_item_main_content</item>
     </style>
 
     <style name="TunerSettings" parent="@android:style/Theme.DeviceDefault.Settings">
@@ -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>
@@ -935,6 +936,10 @@
         <item name="rowStyle">@style/SliceRow</item>
     </style>
 
+    <style name="Widget.SliceView.Panel.Slider">
+        <item name="rowStyle">@style/SliceRow.Slider</item>
+    </style>
+
     <style name="SliceRow">
         <!-- 2dp start padding for the start icon -->
         <item name="titleItemStartPadding">2dp</item>
@@ -956,6 +961,28 @@
         <item name="actionDividerHeight">32dp</item>
     </style>
 
+    <style name="SliceRow.Slider">
+        <!-- Padding between content and the start icon is 5dp -->
+        <item name="contentStartPadding">5dp</item>
+        <item name="contentEndPadding">0dp</item>
+
+        <!-- 0dp start padding for the end item -->
+        <item name="endItemStartPadding">0dp</item>
+        <!-- 8dp end padding for the end item -->
+        <item name="endItemEndPadding">8dp</item>
+
+        <item name="titleSize">20sp</item>
+        <!-- Align text with slider -->
+        <item name="titleStartPadding">11dp</item>
+        <item name="subContentStartPadding">11dp</item>
+
+        <!-- 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">
         <item name="android:textColor">?android:attr/textColorPrimary</item>
         <item name="android:textSize">24sp</item>
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
index 0fac76d..f3866c0 100644
--- a/packages/SystemUI/res/xml/combined_qs_header_scene.xml
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -29,17 +29,15 @@
                 app:percentX="0"
                 app:percentY="0"
                 app:framePosition="49"
-                app:percentWidth="1"
-                app:percentHeight="1"
+                app:sizePercent="0"
                 app:curveFit="linear"
                 app:motionTarget="@id/date" />
             <KeyPosition
                 app:keyPositionType="deltaRelative"
                 app:percentX="1"
                 app:percentY="0.51"
+                app:sizePercent="1"
                 app:framePosition="51"
-                app:percentWidth="1"
-                app:percentHeight="1"
                 app:curveFit="linear"
                 app:motionTarget="@id/date" />
             <KeyAttribute
@@ -64,6 +62,7 @@
                 app:percentX="0"
                 app:percentY="0"
                 app:framePosition="50"
+                app:sizePercent="0"
                 app:curveFit="linear"
                 app:motionTarget="@id/statusIcons" />
             <KeyPosition
@@ -71,6 +70,7 @@
                 app:percentX="1"
                 app:percentY="0.51"
                 app:framePosition="51"
+                app:sizePercent="1"
                 app:curveFit="linear"
                 app:motionTarget="@id/statusIcons" />
             <KeyAttribute
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
new file mode 100644
index 0000000..2e391c7
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
@@ -0,0 +1,99 @@
+/*
+ * 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.testing.screenshot
+
+import android.app.Activity
+import android.graphics.Color
+import android.view.View
+import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
+import androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+import androidx.test.platform.app.InstrumentationRegistry
+import org.junit.rules.RuleChain
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import platform.test.screenshot.*
+
+/**
+ * A rule that allows to run a screenshot diff test on a view that is hosted in another activity.
+ */
+class ExternalViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+
+    private val colorsRule = MaterialYouColorsRule()
+    private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
+    private val screenshotRule =
+        ScreenshotTestRule(
+            SystemUIGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
+        )
+    private val delegateRule =
+        RuleChain.outerRule(colorsRule).around(deviceEmulationRule).around(screenshotRule)
+    private val matcher = UnitTestBitmapMatcher
+
+    override fun apply(base: Statement, description: Description): Statement {
+        return delegateRule.apply(base, description)
+    }
+
+    /**
+     * Compare the content of the [view] with the golden image identified by [goldenIdentifier] in
+     * the context of [emulationSpec].
+     */
+    fun screenshotTest(goldenIdentifier: String, view: View) {
+        view.removeElevationRecursively()
+
+        ScreenshotRuleAsserter.Builder(screenshotRule)
+            .setScreenshotProvider { view.toBitmap() }
+            .withMatcher(matcher)
+            .build()
+            .assertGoldenImage(goldenIdentifier)
+    }
+
+    /**
+     * Compare the content of the [activity] with the golden image identified by [goldenIdentifier]
+     * in the context of [emulationSpec].
+     */
+    fun activityScreenshotTest(
+        goldenIdentifier: String,
+        activity: Activity,
+    ) {
+        val rootView = activity.window.decorView
+
+        // Hide system bars, remove insets, focus and make sure device-specific cutouts
+        // don't affect screenshots
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            val window = activity.window
+            window.setDecorFitsSystemWindows(false)
+            WindowInsetsControllerCompat(window, rootView).apply {
+                hide(WindowInsetsCompat.Type.systemBars())
+                systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+            }
+
+            window.statusBarColor = Color.TRANSPARENT
+            window.navigationBarColor = Color.TRANSPARENT
+            window.attributes =
+                window.attributes.apply {
+                    layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
+                }
+
+            rootView.removeInsetsRecursively()
+            activity.currentFocus?.clearFocus()
+        }
+
+        screenshotTest(goldenIdentifier, rootView)
+    }
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt
new file mode 100644
index 0000000..98e9aaf
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/TestAppComponentFactory.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.testing.screenshot
+
+import android.app.Activity
+import android.content.Intent
+import androidx.core.app.AppComponentFactory
+
+class TestAppComponentFactory : AppComponentFactory() {
+
+    init {
+        instance = this
+    }
+
+    private val overrides: MutableMap<String, () -> Activity> = hashMapOf()
+
+    fun clearOverrides() {
+        overrides.clear()
+    }
+
+    fun <T : Activity> registerActivityOverride(activity: Class<T>, provider: () -> T) {
+        overrides[activity.name] = provider
+    }
+
+    override fun instantiateActivityCompat(
+        cl: ClassLoader,
+        className: String,
+        intent: Intent?
+    ): Activity {
+        return overrides
+            .getOrDefault(className) { super.instantiateActivityCompat(cl, className, intent) }
+            .invoke()
+    }
+
+    companion object {
+
+        private var instance: TestAppComponentFactory? = null
+
+        fun getInstance(): TestAppComponentFactory =
+            instance
+                ?: error(
+                    "TestAppComponentFactory is not initialized, " +
+                        "did you specify it in the manifest?"
+                )
+    }
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
new file mode 100644
index 0000000..b84d26a
--- /dev/null
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/View.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.testing.screenshot
+
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.util.children
+import android.view.WindowInsets
+
+/**
+ * Elevation/shadows is not deterministic when doing hardware rendering, this exentsion allows to
+ * disable it for any view in the hierarchy.
+ */
+fun View.removeElevationRecursively() {
+    this.elevation = 0f
+    (this as? ViewGroup)?.children?.forEach(View::removeElevationRecursively)
+}
+
+/**
+ * Different devices could have different insets (e.g. different height of the navigation bar or
+ * taskbar). This method dispatches empty insets to the whole view hierarchy and removes
+ * the original listener, so the views won't receive real insets.
+ */
+fun View.removeInsetsRecursively() {
+    this.dispatchApplyWindowInsets(WindowInsets.CONSUMED)
+    this.setOnApplyWindowInsetsListener(null)
+    (this as? ViewGroup)?.children?.forEach(View::removeInsetsRecursively)
+}
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
index c609e6f..cdedc64 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewCapture.kt
@@ -1,10 +1,12 @@
 package com.android.systemui.testing.screenshot
 
+import android.annotation.WorkerThread
 import android.app.Activity
 import android.content.Context
 import android.content.ContextWrapper
 import android.graphics.Bitmap
 import android.graphics.Canvas
+import android.graphics.HardwareRenderer
 import android.graphics.Rect
 import android.os.Build
 import android.os.Handler
@@ -19,8 +21,13 @@
 import androidx.concurrent.futures.ResolvableFuture
 import androidx.test.annotation.ExperimentalTestApi
 import androidx.test.core.internal.os.HandlerExecutor
+import androidx.test.espresso.Espresso
 import androidx.test.platform.graphics.HardwareRendererCompat
+import com.google.common.util.concurrent.FutureCallback
+import com.google.common.util.concurrent.Futures
 import com.google.common.util.concurrent.ListenableFuture
+import kotlin.coroutines.suspendCoroutine
+import kotlinx.coroutines.runBlocking
 
 /*
  * This file was forked from androidx/test/core/view/ViewCapture.kt to add [Window] parameter to
@@ -62,6 +69,47 @@
 }
 
 /**
+ * Synchronously captures an image of the view into a [Bitmap]. Synchronous equivalent of
+ * [captureToBitmap].
+ */
+@WorkerThread
+@ExperimentalTestApi
+@RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
+fun View.toBitmap(window: Window? = null): Bitmap {
+    if (Looper.getMainLooper() == Looper.myLooper()) {
+        error("toBitmap() can't be called from the main thread")
+    }
+
+    if (!HardwareRenderer.isDrawingEnabled()) {
+        error("Hardware rendering is not enabled")
+    }
+
+    // Make sure we are idle.
+    Espresso.onIdle()
+
+    val mainExecutor = context.mainExecutor
+    return runBlocking {
+        suspendCoroutine { continuation ->
+            Futures.addCallback(
+                captureToBitmap(window),
+                object : FutureCallback<Bitmap> {
+                    override fun onSuccess(result: Bitmap) {
+                        continuation.resumeWith(Result.success(result))
+                    }
+
+                    override fun onFailure(t: Throwable) {
+                        continuation.resumeWith(Result.failure(t))
+                    }
+                },
+                // We know that we are not on the main thread, so we can block the current
+                // thread and wait for the result in the main thread.
+                mainExecutor,
+            )
+        }
+    }
+}
+
+/**
  * Trigger a redraw of the given view.
  *
  * Should only be called on UI thread.
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 60130e1..0b0595f 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -19,21 +19,13 @@
 import android.app.Activity
 import android.app.Dialog
 import android.graphics.Bitmap
-import android.graphics.HardwareRenderer
-import android.os.Looper
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup.LayoutParams
 import android.view.ViewGroup.LayoutParams.MATCH_PARENT
 import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
-import android.view.Window
 import androidx.activity.ComponentActivity
-import androidx.test.espresso.Espresso
 import androidx.test.ext.junit.rules.ActivityScenarioRule
-import com.google.common.util.concurrent.FutureCallback
-import com.google.common.util.concurrent.Futures
-import kotlin.coroutines.suspendCoroutine
-import kotlinx.coroutines.runBlocking
 import org.junit.Assert.assertEquals
 import org.junit.rules.RuleChain
 import org.junit.rules.TestRule
@@ -44,9 +36,13 @@
 import platform.test.screenshot.MaterialYouColorsRule
 import platform.test.screenshot.ScreenshotTestRule
 import platform.test.screenshot.getEmulatedDevicePathConfig
+import platform.test.screenshot.matchers.BitmapMatcher
 
 /** A rule for View screenshot diff unit tests. */
-class ViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+class ViewScreenshotTestRule(
+    emulationSpec: DeviceEmulationSpec,
+    private val matcher: BitmapMatcher = UnitTestBitmapMatcher
+) : TestRule {
     private val colorsRule = MaterialYouColorsRule()
     private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
     private val screenshotRule =
@@ -59,7 +55,6 @@
             .around(deviceEmulationRule)
             .around(screenshotRule)
             .around(activityRule)
-    private val matcher = UnitTestBitmapMatcher
 
     override fun apply(base: Statement, description: Description): Statement {
         return delegateRule.apply(base, description)
@@ -86,6 +81,8 @@
             // Elevation/shadows is not deterministic when doing hardware rendering, so we disable
             // it for any view in the hierarchy.
             window.decorView.removeElevationRecursively()
+
+            activity.currentFocus?.clearFocus()
         }
 
         // We call onActivity again because it will make sure that our Activity is done measuring,
@@ -147,53 +144,11 @@
         }
     }
 
-    private fun View.removeElevationRecursively() {
-        this.elevation = 0f
-
-        if (this is ViewGroup) {
-            repeat(childCount) { i -> getChildAt(i).removeElevationRecursively() }
-        }
-    }
-
     private fun Dialog.toBitmap(): Bitmap {
         val window = window
         return window.decorView.toBitmap(window)
     }
 
-    private fun View.toBitmap(window: Window? = null): Bitmap {
-        if (Looper.getMainLooper() == Looper.myLooper()) {
-            error("toBitmap() can't be called from the main thread")
-        }
-
-        if (!HardwareRenderer.isDrawingEnabled()) {
-            error("Hardware rendering is not enabled")
-        }
-
-        // Make sure we are idle.
-        Espresso.onIdle()
-
-        val mainExecutor = context.mainExecutor
-        return runBlocking {
-            suspendCoroutine { continuation ->
-                Futures.addCallback(
-                    captureToBitmap(window),
-                    object : FutureCallback<Bitmap> {
-                        override fun onSuccess(result: Bitmap?) {
-                            continuation.resumeWith(Result.success(result!!))
-                        }
-
-                        override fun onFailure(t: Throwable) {
-                            continuation.resumeWith(Result.failure(t))
-                        }
-                    },
-                    // We know that we are not on the main thread, so we can block the current
-                    // thread and wait for the result in the main thread.
-                    mainExecutor,
-                )
-            }
-        }
-    }
-
     enum class Mode(val layoutParams: LayoutParams) {
         WrapContent(LayoutParams(WRAP_CONTENT, WRAP_CONTENT)),
         MatchSize(LayoutParams(MATCH_PARENT, MATCH_PARENT)),
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/res/layout/clock_default_small.xml b/packages/SystemUI/shared/res/layout/clock_default_small.xml
index 390ff5e..ff6d7f9 100644
--- a/packages/SystemUI/shared/res/layout/clock_default_small.xml
+++ b/packages/SystemUI/shared/res/layout/clock_default_small.xml
@@ -18,7 +18,7 @@
 -->
 <com.android.systemui.shared.clocks.AnimatableClockView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
+    android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="start"
     android:gravity="start"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index a21a78b..34e2e83 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -29,6 +29,7 @@
 import android.widget.TextView
 import com.android.internal.R.attr.contentDescription
 import com.android.internal.R.attr.format
+import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.animation.GlyphCallback
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.TextAnimator
@@ -77,6 +78,9 @@
     private var textAnimator: TextAnimator? = null
     private var onTextAnimatorInitialized: Runnable? = null
 
+    @VisibleForTesting var isAnimationEnabled: Boolean = true
+    @VisibleForTesting var timeOverrideInMillis: Long? = null
+
     val dozingWeight: Int
         get() = if (useBoldedVersion()) dozingWeightInternal + 100 else dozingWeightInternal
 
@@ -139,7 +143,7 @@
     }
 
     fun refreshTime() {
-        time.timeInMillis = System.currentTimeMillis()
+        time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis()
         contentDescription = DateFormat.format(descFormat, time)
         val formattedText = DateFormat.format(format, time)
         // Setting text actually triggers a layout pass (because the text view is set to
@@ -215,7 +219,7 @@
     }
 
     fun animateAppearOnLockscreen() {
-        if (textAnimator == null) {
+        if (isAnimationEnabled && textAnimator == null) {
             return
         }
         setTextStyle(
@@ -231,7 +235,7 @@
             weight = lockScreenWeight,
             textSize = -1f,
             color = lockScreenColor,
-            animate = true,
+            animate = isAnimationEnabled,
             duration = APPEAR_ANIM_DURATION,
             delay = 0,
             onAnimationEnd = null
@@ -239,7 +243,7 @@
     }
 
     fun animateFoldAppear(animate: Boolean = true) {
-        if (textAnimator == null) {
+        if (isAnimationEnabled && textAnimator == null) {
             return
         }
         setTextStyle(
@@ -255,7 +259,7 @@
             weight = dozingWeightInternal,
             textSize = -1f,
             color = dozingColor,
-            animate = animate,
+            animate = animate && isAnimationEnabled,
             interpolator = Interpolators.EMPHASIZED_DECELERATE,
             duration = ANIMATION_DURATION_FOLD_TO_AOD.toLong(),
             delay = 0,
@@ -273,7 +277,7 @@
                 weight = if (isDozing()) dozingWeight else lockScreenWeight,
                 textSize = -1f,
                 color = null,
-                animate = true,
+                animate = isAnimationEnabled,
                 duration = CHARGE_ANIM_DURATION_PHASE_1,
                 delay = 0,
                 onAnimationEnd = null
@@ -283,7 +287,7 @@
             weight = if (isDozing()) lockScreenWeight else dozingWeight,
             textSize = -1f,
             color = null,
-            animate = true,
+            animate = isAnimationEnabled,
             duration = CHARGE_ANIM_DURATION_PHASE_0,
             delay = chargeAnimationDelay.toLong(),
             onAnimationEnd = startAnimPhase2
@@ -295,7 +299,7 @@
             weight = if (isDozing) dozingWeight else lockScreenWeight,
             textSize = -1f,
             color = if (isDozing) dozingColor else lockScreenColor,
-            animate = animate,
+            animate = animate && isAnimationEnabled,
             duration = DOZE_ANIM_DURATION,
             delay = 0,
             onAnimationEnd = null
@@ -329,7 +333,7 @@
                 weight = weight,
                 textSize = textSize,
                 color = color,
-                animate = animate,
+                animate = animate && isAnimationEnabled,
                 duration = duration,
                 interpolator = interpolator,
                 delay = delay,
@@ -367,7 +371,7 @@
             weight = weight,
             textSize = textSize,
             color = color,
-            animate = animate,
+            animate = animate && isAnimationEnabled,
             interpolator = null,
             duration = duration,
             delay = delay,
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
index 6c49186..19ac2e4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt
@@ -13,12 +13,15 @@
  */
 package com.android.systemui.shared.clocks
 
+import android.content.Context
 import android.content.res.Resources
 import android.graphics.Color
 import android.graphics.drawable.Drawable
 import android.icu.text.NumberFormat
 import android.util.TypedValue
 import android.view.LayoutInflater
+import android.widget.FrameLayout
+import com.android.internal.annotations.VisibleForTesting
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.Clock
 import com.android.systemui.plugins.ClockAnimations
@@ -27,7 +30,6 @@
 import com.android.systemui.plugins.ClockMetadata
 import com.android.systemui.plugins.ClockProvider
 import com.android.systemui.shared.R
-import com.android.systemui.shared.regionsampling.RegionDarkness
 import java.io.PrintWriter
 import java.util.Locale
 import java.util.TimeZone
@@ -39,6 +41,7 @@
 
 /** Provides the default system clock */
 class DefaultClockProvider @Inject constructor(
+    val ctx: Context,
     val layoutInflater: LayoutInflater,
     @Main val resources: Resources
 ) : ClockProvider {
@@ -49,7 +52,7 @@
         if (id != DEFAULT_CLOCK_ID) {
             throw IllegalArgumentException("$id is unsupported by $TAG")
         }
-        return DefaultClock(layoutInflater, resources)
+        return DefaultClock(ctx, layoutInflater, resources)
     }
 
     override fun getClockThumbnail(id: ClockId): Drawable? {
@@ -69,14 +72,13 @@
  * AnimatableClockView used by the existing lockscreen clock.
  */
 class DefaultClock(
+        ctx: Context,
         private val layoutInflater: LayoutInflater,
         private val resources: Resources
 ) : Clock {
-    override val smallClock =
-        layoutInflater.inflate(R.layout.clock_default_small, null) as AnimatableClockView
-    override val largeClock =
-        layoutInflater.inflate(R.layout.clock_default_large, null) as AnimatableClockView
-    private val clocks = listOf(smallClock, largeClock)
+    override val smallClock: AnimatableClockView
+    override val largeClock: AnimatableClockView
+    private val clocks get() = listOf(smallClock, largeClock)
 
     private val burmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my"))
     private val burmeseNumerals = burmeseNf.format(FORMAT_NUMBER.toLong())
@@ -84,20 +86,46 @@
         resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese)
     private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale)
 
-    private var smallRegionDarkness = RegionDarkness.DEFAULT
-    private var largeRegionDarkness = RegionDarkness.DEFAULT
+    override val events: ClockEvents
+    override lateinit var animations: ClockAnimations
+        private set
 
-    private fun updateClockColor(clock: AnimatableClockView, isRegionDark: RegionDarkness) {
-        val color = if (isRegionDark.isDark) {
-            resources.getColor(android.R.color.system_accent2_100)
-        } else {
-            resources.getColor(android.R.color.system_accent1_600)
-        }
-        clock.setColors(DOZE_COLOR, color)
-        clock.animateAppearOnLockscreen()
+    private var smallRegionDarkness = false
+    private var largeRegionDarkness = false
+
+    init {
+        val parent = FrameLayout(ctx)
+
+        smallClock = layoutInflater.inflate(
+            R.layout.clock_default_small,
+            parent,
+            false
+        ) as AnimatableClockView
+
+        largeClock = layoutInflater.inflate(
+            R.layout.clock_default_large,
+            parent,
+            false
+        ) as AnimatableClockView
+
+        events = DefaultClockEvents()
+        animations = DefaultClockAnimations(0f, 0f)
+
+        events.onLocaleChanged(Locale.getDefault())
+
+        // DOZE_COLOR is a placeholder, and will be assigned correctly in initialize
+        clocks.forEach { it.setColors(DOZE_COLOR, DOZE_COLOR) }
     }
 
-    override val events = object : ClockEvents {
+    override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
+        recomputePadding()
+        animations = DefaultClockAnimations(dozeFraction, foldFraction)
+        events.onColorPaletteChanged(resources, true, true)
+        events.onTimeZoneChanged(TimeZone.getDefault())
+        events.onTimeTick()
+    }
+
+    inner class DefaultClockEvents() : ClockEvents {
         override fun onTimeTick() = clocks.forEach { it.refreshTime() }
 
         override fun onTimeFormatChanged(is24Hr: Boolean) =
@@ -120,8 +148,8 @@
 
         override fun onColorPaletteChanged(
                 resources: Resources,
-                smallClockIsDark: RegionDarkness,
-                largeClockIsDark: RegionDarkness
+                smallClockIsDark: Boolean,
+                largeClockIsDark: Boolean
         ) {
             if (smallRegionDarkness != smallClockIsDark) {
                 smallRegionDarkness = smallClockIsDark
@@ -145,9 +173,6 @@
         }
     }
 
-    override var animations = DefaultClockAnimations(0f, 0f)
-        private set
-
     inner class DefaultClockAnimations(
         dozeFraction: Float,
         foldFraction: Float
@@ -203,35 +228,26 @@
         }
     }
 
-    init {
-        events.onLocaleChanged(Locale.getDefault())
-        clocks.forEach { it.setColors(DOZE_COLOR, DOZE_COLOR) }
-    }
-
-    override fun initialize(
-            resources: Resources,
-            dozeFraction: Float,
-            foldFraction: Float
-    ) {
-        recomputePadding()
-        animations = DefaultClockAnimations(dozeFraction, foldFraction)
-        events.onColorPaletteChanged(
-                resources,
-                RegionDarkness.DEFAULT,
-                RegionDarkness.DEFAULT
-        )
-        events.onTimeTick()
+    private fun updateClockColor(clock: AnimatableClockView, isRegionDark: Boolean) {
+        val color = if (isRegionDark) {
+            resources.getColor(android.R.color.system_accent1_100)
+        } else {
+            resources.getColor(android.R.color.system_accent2_600)
+        }
+        clock.setColors(DOZE_COLOR, color)
+        clock.animateAppearOnLockscreen()
     }
 
     private fun recomputePadding() {
-        val topPadding = -1 * (largeClock.bottom.toInt() - 180)
-        largeClock.setPadding(0, topPadding, 0, 0)
+        val lp = largeClock.getLayoutParams() as FrameLayout.LayoutParams
+        lp.topMargin = (-0.5f * largeClock.bottom).toInt()
+        largeClock.setLayoutParams(lp)
     }
 
     override fun dump(pw: PrintWriter) = clocks.forEach { it.dump(pw) }
 
     companion object {
-        private const val DOZE_COLOR = Color.WHITE
+        @VisibleForTesting const val DOZE_COLOR = Color.WHITE
         private const val FORMAT_NUMBER = 1234567890
     }
 }
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/plugin/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
similarity index 100%
rename from packages/SystemUI/plugin/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
rename to packages/SystemUI/shared/src/com/android/systemui/shared/regionsampling/RegionDarkness.kt
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/ContextUtils.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
deleted file mode 100644
index 1de740a..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ContextUtils.java
+++ /dev/null
@@ -1,28 +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.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();
-    }
-}
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/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 0d1158c..0e1e0cb 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -21,6 +21,8 @@
 import android.content.IntentFilter
 import android.content.res.Resources
 import android.text.format.DateFormat
+import android.util.TypedValue
+import android.view.View
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -41,7 +43,7 @@
  * Controller for a Clock provided by the registry and used on the keyguard. Instantiated by
  * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController].
  */
-class ClockEventController @Inject constructor(
+open class ClockEventController @Inject constructor(
         private val statusBarStateController: StatusBarStateController,
         private val broadcastDispatcher: BroadcastDispatcher,
         private val batteryController: BatteryController,
@@ -74,18 +76,21 @@
 
     private val updateFun = object : RegionSamplingInstance.UpdateColorCallback {
         override fun updateColors() {
-            smallClockIsDark = smallRegionSamplingInstance.currentRegionDarkness()
-            largeClockIsDark = largeRegionSamplingInstance.currentRegionDarkness()
-
+            if (regionSamplingEnabled) {
+                smallClockIsDark = smallRegionSamplingInstance.currentRegionDarkness().isDark
+                largeClockIsDark = largeRegionSamplingInstance.currentRegionDarkness().isDark
+            } else {
+                val isLightTheme = TypedValue()
+                context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
+                smallClockIsDark = isLightTheme.data == 0
+                largeClockIsDark = isLightTheme.data == 0
+            }
             clock?.events?.onColorPaletteChanged(resources, smallClockIsDark, largeClockIsDark)
         }
     }
 
     fun updateRegionSamplers(currentClock: Clock?) {
-        smallRegionSamplingInstance.stopRegionSampler()
-        largeRegionSamplingInstance.stopRegionSampler()
-
-        smallRegionSamplingInstance = RegionSamplingInstance(
+        smallRegionSamplingInstance = createRegionSampler(
                 currentClock?.smallClock,
                 mainExecutor,
                 bgExecutor,
@@ -93,7 +98,7 @@
                 updateFun
         )
 
-        largeRegionSamplingInstance = RegionSamplingInstance(
+        largeRegionSamplingInstance = createRegionSampler(
                 currentClock?.largeClock,
                 mainExecutor,
                 bgExecutor,
@@ -107,24 +112,26 @@
         updateFun.updateColors()
     }
 
-    var smallRegionSamplingInstance: RegionSamplingInstance = RegionSamplingInstance(
-            clock?.smallClock,
+    protected open fun createRegionSampler(
+            sampledView: View?,
+            mainExecutor: Executor?,
+            bgExecutor: Executor?,
+            regionSamplingEnabled: Boolean,
+            updateFun: RegionSamplingInstance.UpdateColorCallback
+    ): RegionSamplingInstance {
+        return RegionSamplingInstance(
+            sampledView,
             mainExecutor,
             bgExecutor,
             regionSamplingEnabled,
-            updateFun
-    )
+            updateFun)
+    }
 
-    var largeRegionSamplingInstance: RegionSamplingInstance = RegionSamplingInstance(
-            clock?.largeClock,
-            mainExecutor,
-            bgExecutor,
-            regionSamplingEnabled,
-            updateFun
-    )
+    lateinit var smallRegionSamplingInstance: RegionSamplingInstance
+    lateinit var largeRegionSamplingInstance: RegionSamplingInstance
 
-    private var smallClockIsDark = smallRegionSamplingInstance.currentRegionDarkness()
-    private var largeClockIsDark = largeRegionSamplingInstance.currentRegionDarkness()
+    private var smallClockIsDark = true
+    private var largeClockIsDark = true
 
     private val configListener = object : ConfigurationController.ConfigurationListener {
         override fun onThemeChanged() {
@@ -179,7 +186,6 @@
 
     init {
         isDozing = statusBarStateController.isDozing
-        clock?.events?.onColorPaletteChanged(resources, smallClockIsDark, largeClockIsDark)
     }
 
     fun registerListeners() {
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
new file mode 100644
index 0000000..6fcb6f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.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.keyguard
+
+import android.annotation.StringDef
+import com.android.internal.logging.UiEvent
+import com.android.internal.logging.UiEventLogger
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.NOTIFICATION_PANEL_CLICKED
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.PICK_UP_GESTURE_TRIGGERED
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.QS_EXPANDED
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.SWIPE_UP_ON_BOUNCER
+import com.android.keyguard.FaceAuthApiRequestReason.Companion.UDFPS_POINTER_DOWN
+import com.android.keyguard.InternalFaceAuthReasons.ALL_AUTHENTICATORS_REGISTERED
+import com.android.keyguard.InternalFaceAuthReasons.ALTERNATE_BIOMETRIC_BOUNCER_SHOWN
+import com.android.keyguard.InternalFaceAuthReasons.ASSISTANT_VISIBILITY_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLATION
+import com.android.keyguard.InternalFaceAuthReasons.BIOMETRIC_ENABLED
+import com.android.keyguard.InternalFaceAuthReasons.CAMERA_LAUNCHED
+import com.android.keyguard.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE
+import com.android.keyguard.InternalFaceAuthReasons.DREAM_STARTED
+import com.android.keyguard.InternalFaceAuthReasons.DREAM_STOPPED
+import com.android.keyguard.InternalFaceAuthReasons.ENROLLMENTS_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.FACE_AUTHENTICATED
+import com.android.keyguard.InternalFaceAuthReasons.FACE_AUTH_STOPPED_ON_USER_INPUT
+import com.android.keyguard.InternalFaceAuthReasons.FACE_CANCEL_NOT_RECEIVED
+import com.android.keyguard.InternalFaceAuthReasons.FACE_LOCKOUT_RESET
+import com.android.keyguard.InternalFaceAuthReasons.FINISHED_GOING_TO_SLEEP
+import com.android.keyguard.InternalFaceAuthReasons.FP_AUTHENTICATED
+import com.android.keyguard.InternalFaceAuthReasons.FP_LOCKED_OUT
+import com.android.keyguard.InternalFaceAuthReasons.GOING_TO_SLEEP
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_GOING_AWAY
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_INIT
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_OCCLUSION_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_RESET
+import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_VISIBILITY_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.OCCLUDING_APP_REQUESTED
+import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN
+import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
+import com.android.keyguard.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE
+import com.android.keyguard.InternalFaceAuthReasons.STARTED_WAKING_UP
+import com.android.keyguard.InternalFaceAuthReasons.TRUST_DISABLED
+import com.android.keyguard.InternalFaceAuthReasons.TRUST_ENABLED
+import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING
+
+/**
+ * List of reasons why face auth is requested by clients through
+ * [KeyguardUpdateMonitor.requestFaceAuth].
+ */
+@Retention(AnnotationRetention.SOURCE)
+@StringDef(
+    SWIPE_UP_ON_BOUNCER,
+    UDFPS_POINTER_DOWN,
+    NOTIFICATION_PANEL_CLICKED,
+    QS_EXPANDED,
+    PICK_UP_GESTURE_TRIGGERED,
+)
+annotation class FaceAuthApiRequestReason {
+    companion object {
+        const val SWIPE_UP_ON_BOUNCER = "Face auth due to swipe up on bouncer"
+        const val UDFPS_POINTER_DOWN = "Face auth triggered due to finger down on UDFPS"
+        const val NOTIFICATION_PANEL_CLICKED = "Face auth due to notification panel click."
+        const val QS_EXPANDED = "Face auth due to QS expansion."
+        const val PICK_UP_GESTURE_TRIGGERED =
+            "Face auth due to pickup gesture triggered when the device is awake and not from AOD."
+    }
+}
+
+/** List of events why face auth could be triggered by [KeyguardUpdateMonitor]. */
+private object InternalFaceAuthReasons {
+    const val OCCLUDING_APP_REQUESTED = "Face auth due to request from occluding app."
+    const val RETRY_AFTER_HW_UNAVAILABLE = "Face auth due to retry after hardware unavailable."
+    const val FACE_LOCKOUT_RESET = "Face auth due to face lockout reset."
+    const val DEVICE_WOKEN_UP_ON_REACH_GESTURE =
+        "Face auth requested when user reaches for the device on AoD."
+    const val ALTERNATE_BIOMETRIC_BOUNCER_SHOWN = "Face auth due to alternate bouncer shown."
+    const val PRIMARY_BOUNCER_SHOWN = "Face auth started/stopped due to primary bouncer shown."
+    const val PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN =
+        "Face auth started/stopped due to bouncer being shown or will be shown."
+    const val TRUST_DISABLED = "Face auth started due to trust disabled."
+    const val TRUST_ENABLED = "Face auth stopped due to trust enabled."
+    const val KEYGUARD_OCCLUSION_CHANGED =
+        "Face auth started/stopped due to keyguard occlusion change."
+    const val ASSISTANT_VISIBILITY_CHANGED =
+        "Face auth started/stopped due to assistant visibility change."
+    const val STARTED_WAKING_UP = "Face auth started/stopped due to device starting to wake up."
+    const val DREAM_STOPPED = "Face auth due to dream stopped."
+    const val ALL_AUTHENTICATORS_REGISTERED = "Face auth due to all authenticators registered."
+    const val ENROLLMENTS_CHANGED = "Face auth due to enrolments changed."
+    const val KEYGUARD_VISIBILITY_CHANGED =
+        "Face auth stopped or started due to keyguard visibility changed."
+    const val FACE_CANCEL_NOT_RECEIVED = "Face auth stopped due to face cancel signal not received."
+    const val AUTH_REQUEST_DURING_CANCELLATION =
+        "Another request to start face auth received while cancelling face auth"
+    const val DREAM_STARTED = "Face auth stopped because dreaming started"
+    const val FP_LOCKED_OUT = "Face auth stopped because fp locked out"
+    const val FACE_AUTH_STOPPED_ON_USER_INPUT =
+        "Face auth stopped because user started typing password/pin"
+    const val KEYGUARD_GOING_AWAY = "Face auth stopped because keyguard going away"
+    const val CAMERA_LAUNCHED = "Face auth started/stopped because camera launched"
+    const val FP_AUTHENTICATED = "Face auth started/stopped because fingerprint launched"
+    const val GOING_TO_SLEEP = "Face auth started/stopped because going to sleep"
+    const val FINISHED_GOING_TO_SLEEP = "Face auth stopped because finished going to sleep"
+    const val KEYGUARD_INIT = "Face auth started/stopped because Keyguard is initialized"
+    const val KEYGUARD_RESET = "Face auth started/stopped because Keyguard is reset"
+    const val USER_SWITCHING = "Face auth started/stopped because user is switching"
+    const val FACE_AUTHENTICATED = "Face auth started/stopped because face is authenticated"
+    const val BIOMETRIC_ENABLED =
+        "Face auth started/stopped because biometric is enabled on keyguard"
+}
+
+/** UiEvents that are logged to identify why face auth is being triggered. */
+enum class FaceAuthUiEvent constructor(private val id: Int, val reason: String) :
+    UiEventLogger.UiEventEnum {
+    @UiEvent(doc = OCCLUDING_APP_REQUESTED)
+    FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED(1146, OCCLUDING_APP_REQUESTED),
+
+    @UiEvent(doc = UDFPS_POINTER_DOWN)
+    FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN(1147, UDFPS_POINTER_DOWN),
+
+    @UiEvent(doc = SWIPE_UP_ON_BOUNCER)
+    FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER(1148, SWIPE_UP_ON_BOUNCER),
+
+    @UiEvent(doc = DEVICE_WOKEN_UP_ON_REACH_GESTURE)
+    FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD(1149, DEVICE_WOKEN_UP_ON_REACH_GESTURE),
+
+    @UiEvent(doc = FACE_LOCKOUT_RESET)
+    FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET(1150, FACE_LOCKOUT_RESET),
+
+    @UiEvent(doc = QS_EXPANDED)
+    FACE_AUTH_TRIGGERED_QS_EXPANDED(1151, QS_EXPANDED),
+
+    @UiEvent(doc = NOTIFICATION_PANEL_CLICKED)
+    FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED(1152, NOTIFICATION_PANEL_CLICKED),
+
+    @UiEvent(doc = PICK_UP_GESTURE_TRIGGERED)
+    FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED(1153, PICK_UP_GESTURE_TRIGGERED),
+
+    @UiEvent(doc = ALTERNATE_BIOMETRIC_BOUNCER_SHOWN)
+    FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN(1154,
+        ALTERNATE_BIOMETRIC_BOUNCER_SHOWN),
+
+    @UiEvent(doc = PRIMARY_BOUNCER_SHOWN)
+    FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN(1155, PRIMARY_BOUNCER_SHOWN),
+
+    @UiEvent(doc = PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN)
+    FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN(
+        1197,
+        PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
+    ),
+
+    @UiEvent(doc = RETRY_AFTER_HW_UNAVAILABLE)
+    FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE(1156, RETRY_AFTER_HW_UNAVAILABLE),
+
+    @UiEvent(doc = TRUST_DISABLED)
+    FACE_AUTH_TRIGGERED_TRUST_DISABLED(1158, TRUST_DISABLED),
+
+    @UiEvent(doc = TRUST_ENABLED)
+    FACE_AUTH_STOPPED_TRUST_ENABLED(1173, TRUST_ENABLED),
+
+    @UiEvent(doc = KEYGUARD_OCCLUSION_CHANGED)
+    FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED(1159, KEYGUARD_OCCLUSION_CHANGED),
+
+    @UiEvent(doc = ASSISTANT_VISIBILITY_CHANGED)
+    FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED(1160, ASSISTANT_VISIBILITY_CHANGED),
+
+    @UiEvent(doc = STARTED_WAKING_UP)
+    FACE_AUTH_UPDATED_STARTED_WAKING_UP(1161, STARTED_WAKING_UP),
+
+    @UiEvent(doc = DREAM_STOPPED)
+    FACE_AUTH_TRIGGERED_DREAM_STOPPED(1162, DREAM_STOPPED),
+
+    @UiEvent(doc = ALL_AUTHENTICATORS_REGISTERED)
+    FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED(1163, ALL_AUTHENTICATORS_REGISTERED),
+
+    @UiEvent(doc = ENROLLMENTS_CHANGED)
+    FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED(1164, ENROLLMENTS_CHANGED),
+
+    @UiEvent(doc = KEYGUARD_VISIBILITY_CHANGED)
+    FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED(1165, KEYGUARD_VISIBILITY_CHANGED),
+
+    @UiEvent(doc = FACE_CANCEL_NOT_RECEIVED)
+    FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED(1174, FACE_CANCEL_NOT_RECEIVED),
+
+    @UiEvent(doc = AUTH_REQUEST_DURING_CANCELLATION)
+    FACE_AUTH_TRIGGERED_DURING_CANCELLATION(1175, AUTH_REQUEST_DURING_CANCELLATION),
+
+    @UiEvent(doc = DREAM_STARTED)
+    FACE_AUTH_STOPPED_DREAM_STARTED(1176, DREAM_STARTED),
+
+    @UiEvent(doc = FP_LOCKED_OUT)
+    FACE_AUTH_STOPPED_FP_LOCKED_OUT(1177, FP_LOCKED_OUT),
+
+    @UiEvent(doc = FACE_AUTH_STOPPED_ON_USER_INPUT)
+    FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER(1178, FACE_AUTH_STOPPED_ON_USER_INPUT),
+
+    @UiEvent(doc = KEYGUARD_GOING_AWAY)
+    FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY(1179, KEYGUARD_GOING_AWAY),
+
+    @UiEvent(doc = CAMERA_LAUNCHED)
+    FACE_AUTH_UPDATED_CAMERA_LAUNCHED(1180, CAMERA_LAUNCHED),
+
+    @UiEvent(doc = FP_AUTHENTICATED)
+    FACE_AUTH_UPDATED_FP_AUTHENTICATED(1181, FP_AUTHENTICATED),
+
+    @UiEvent(doc = GOING_TO_SLEEP)
+    FACE_AUTH_UPDATED_GOING_TO_SLEEP(1182, GOING_TO_SLEEP),
+
+    @UiEvent(doc = FINISHED_GOING_TO_SLEEP)
+    FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP(1183, FINISHED_GOING_TO_SLEEP),
+
+    @UiEvent(doc = KEYGUARD_INIT)
+    FACE_AUTH_UPDATED_ON_KEYGUARD_INIT(1189, KEYGUARD_INIT),
+
+    @UiEvent(doc = KEYGUARD_RESET)
+    FACE_AUTH_UPDATED_KEYGUARD_RESET(1185, KEYGUARD_RESET),
+
+    @UiEvent(doc = USER_SWITCHING)
+    FACE_AUTH_UPDATED_USER_SWITCHING(1186, USER_SWITCHING),
+
+    @UiEvent(doc = FACE_AUTHENTICATED)
+    FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED(1187, FACE_AUTHENTICATED),
+
+    @UiEvent(doc = BIOMETRIC_ENABLED)
+    FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED);
+
+    override fun getId(): Int = this.id
+}
+
+private val apiRequestReasonToUiEvent =
+    mapOf(
+        SWIPE_UP_ON_BOUNCER to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER,
+        UDFPS_POINTER_DOWN to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_UDFPS_POINTER_DOWN,
+        NOTIFICATION_PANEL_CLICKED to
+            FaceAuthUiEvent.FACE_AUTH_TRIGGERED_NOTIFICATION_PANEL_CLICKED,
+        QS_EXPANDED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_QS_EXPANDED,
+        PICK_UP_GESTURE_TRIGGERED to FaceAuthUiEvent.FACE_AUTH_TRIGGERED_PICK_UP_GESTURE_TRIGGERED,
+    )
+
+/** Converts the [reason] to the corresponding [FaceAuthUiEvent]. */
+fun apiRequestReasonToUiEvent(@FaceAuthApiRequestReason reason: String): FaceAuthUiEvent =
+    apiRequestReasonToUiEvent[reason]!!
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/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index e1fabde..d7cd1d0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -8,7 +8,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.RelativeLayout;
 
@@ -68,6 +67,7 @@
 
     private int mClockSwitchYAmount;
     @VisibleForTesting boolean mChildrenAreLaidOut = false;
+    @VisibleForTesting boolean mAnimateOnLayout = true;
 
     public KeyguardClockSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -105,9 +105,7 @@
         }
 
         // Attach small and big clock views to hierarchy.
-        mSmallClockFrame.addView(clock.getSmallClock(), -1,
-                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT));
+        mSmallClockFrame.addView(clock.getSmallClock());
         mLargeClockFrame.addView(clock.getLargeClock());
     }
 
@@ -214,7 +212,7 @@
         super.onLayout(changed, l, t, r, b);
 
         if (mDisplayedClockSize != null && !mChildrenAreLaidOut) {
-            post(() -> updateClockViews(mDisplayedClockSize == LARGE, /* animate */ true));
+            post(() -> updateClockViews(mDisplayedClockSize == LARGE, mAnimateOnLayout));
         }
 
         mChildrenAreLaidOut = true;
@@ -222,7 +220,7 @@
 
     public void dump(PrintWriter pw, String[] args) {
         pw.println("KeyguardClockSwitch:");
-        pw.println("  mClockFrame: " + mSmallClockFrame);
+        pw.println("  mSmallClockFrame: " + mSmallClockFrame);
         pw.println("  mLargeClockFrame: " + mLargeClockFrame);
         pw.println("  mStatusArea: " + mStatusArea);
         pw.println("  mDisplayedClockSize: " + mDisplayedClockSize);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index dd78f1c..2165099 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -72,7 +72,6 @@
     private final DumpManager mDumpManager;
     private final ClockEventController mClockEventController;
 
-    /** Clock frames for both small and large sizes */
     private FrameLayout mSmallClockFrame; // top aligned clock
     private FrameLayout mLargeClockFrame; // centered clock
 
@@ -151,7 +150,7 @@
      * Attach the controller to the view it relates to.
      */
     @Override
-    public void onInit() {
+    protected void onInit() {
         mKeyguardSliceViewController.init();
 
         mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
@@ -390,8 +389,6 @@
      * bounds during the unlock transition.
      */
     private void setClipChildrenForUnlock(boolean clip) {
-        mView.setClipChildren(clip);
-
         if (mStatusArea != null) {
             mStatusArea.setClipChildren(clip);
         }
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 0ea1965..919b71b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -52,6 +52,7 @@
     val becauseCannotSkipBouncer: Boolean,
     val biometricSettingEnabledForUser: Boolean,
     val bouncerFullyShown: Boolean,
+    val bouncerIsOrWillShow: Boolean,
     val faceAuthenticated: Boolean,
     val faceDisabled: Boolean,
     val goingToSleep: Boolean,
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..20fa8f8 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,7 +42,7 @@
  */
 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;
@@ -54,7 +56,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(
@@ -169,25 +170,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 +191,6 @@
         disappearAnimationUtils.createAnimation(
                 this, 0, 200, mDisappearYTranslation, false,
                 mDisappearAnimationUtils.getInterpolator(), () -> {
-                    enableClipping(true);
                     if (finishRunnable != null) {
                         finishRunnable.run();
                     }
@@ -204,14 +199,32 @@
         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) {
+        for (int i = 0; i < mViews.length; i++) {
+            View[] row = mViews[i];
+            for (View view : row) {
+                if (view == null) {
+                    continue;
+                }
+
+                float scaledProgress = MathUtils.constrain(
+                        (progress - 0.075f * i) / (1f - 0.075f * mViews.length),
+                        0f,
+                        1f
+                );
+                view.setAlpha(scaledProgress);
+                Interpolator interpolator = Interpolators.STANDARD_ACCELERATE;
+                view.setTranslationY(40 - (40 * interpolator.getInterpolation(scaledProgress)));
+                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/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 3517d22..f73c98e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -89,7 +89,7 @@
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter;
-import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord;
+import com.android.systemui.user.data.source.UserRecord;
 import com.android.systemui.util.settings.GlobalSettings;
 
 import java.util.ArrayList;
@@ -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/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index e1957c0..57058b7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -223,7 +223,7 @@
         @Override
         public void onSwipeUp() {
             if (!mUpdateMonitor.isFaceDetectionRunning()) {
-                mUpdateMonitor.requestFaceAuth(true);
+                mUpdateMonitor.requestFaceAuth(true, FaceAuthApiRequestReason.SWIPE_UP_ON_BOUNCER);
                 mKeyguardSecurityCallback.userActivity();
                 showMessage(null, null);
             }
@@ -418,6 +418,7 @@
             SysUiStatsLog.write(SysUiStatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, state);
 
             getCurrentSecurityController().onResume(reason);
+            updateSideFpsVisibility();
         }
         mView.onResume(
                 mSecurityModel.getSecurityMode(KeyguardUpdateMonitor.getCurrentUser()),
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/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 98bc28d..1463840 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import static android.app.StatusBarManager.SESSION_KEYGUARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.content.Intent.ACTION_USER_REMOVED;
@@ -25,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;
@@ -32,11 +34,43 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FP_LOCKED_OUT;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_TRUST_ENABLED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_DREAM_STOPPED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_DURING_CANCELLATION;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_TRUST_DISABLED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_CAMERA_LAUNCHED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_FP_AUTHENTICATED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_GOING_TO_SLEEP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_RESET;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.ActivityTaskManager.RootTaskInfo;
@@ -71,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;
@@ -92,6 +128,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
@@ -105,6 +143,7 @@
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -130,6 +169,7 @@
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 
 /**
  * Watches for updates that may be interesting to the keyguard, and provides
@@ -225,6 +265,7 @@
     private final boolean mIsPrimaryUser;
     private final AuthController mAuthController;
     private final StatusBarStateController mStatusBarStateController;
+    private final UiEventLogger mUiEventLogger;
     private int mStatusBarState;
     private final StatusBarStateController.StateListener mStatusBarStateControllerListener =
             new StatusBarStateController.StateListener() {
@@ -290,7 +331,6 @@
     private KeyguardBypassController mKeyguardBypassController;
     private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
     private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
-    private boolean mIsFaceAuthUserRequested;
     private LockPatternUtils mLockPatternUtils;
     private final IDreamManager mDreamManager;
     private boolean mIsDreaming;
@@ -304,6 +344,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
@@ -322,6 +364,7 @@
     protected final Runnable mFpCancelNotReceived = this::onFingerprintCancelNotReceived;
 
     private final Runnable mFaceCancelNotReceived = this::onFaceCancelNotReceived;
+    private final Provider<SessionTracker> mSessionTrackerProvider;
 
     @VisibleForTesting
     protected Handler getHandler() {
@@ -337,7 +380,8 @@
                 public void onChanged(boolean enabled, int userId) throws RemoteException {
                     mHandler.post(() -> {
                         mBiometricEnabledForUser.put(userId, enabled);
-                        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+                        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                                FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD);
                     });
                 }
             };
@@ -405,11 +449,14 @@
         // authenticating.  TrustManager sends an onTrustChanged whenever a user unlocks keyguard,
         // for this reason we need to make sure to not authenticate.
         if (wasTrusted == enabled || enabled) {
-            updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+            updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
+                    FACE_AUTH_STOPPED_TRUST_ENABLED);
         } else {
-            updateBiometricListeningState(BIOMETRIC_ACTION_START);
+            updateBiometricListeningState(BIOMETRIC_ACTION_START,
+                    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) {
@@ -425,12 +472,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) {
@@ -601,7 +652,7 @@
     public void setKeyguardGoingAway(boolean goingAway) {
         mKeyguardGoingAway = goingAway;
         // This is set specifically to stop face authentication from running.
-        updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+        updateBiometricListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_KEYGUARD_GOING_AWAY);
     }
 
     /**
@@ -609,7 +660,8 @@
      */
     public void setKeyguardOccluded(boolean occluded) {
         mKeyguardOccluded = occluded;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED);
     }
 
 
@@ -621,7 +673,8 @@
      */
     public void requestFaceAuthOnOccludingApp(boolean request) {
         mOccludingAppRequestingFace = request;
-        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED);
     }
 
     /**
@@ -640,7 +693,8 @@
      */
     public void onCameraLaunched() {
         mSecureCameraLaunched = true;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_UPDATED_CAMERA_LAUNCHED);
     }
 
     /**
@@ -682,7 +736,9 @@
         }
         // Don't send cancel if authentication succeeds
         mFingerprintCancelSignal = null;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        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) {
@@ -739,6 +795,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) {
@@ -845,7 +906,7 @@
             if (isUdfpsEnrolled()) {
                 updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
             }
-            stopListeningForFace();
+            stopListeningForFace(FACE_AUTH_STOPPED_FP_LOCKED_OUT);
         }
 
         for (int i = 0; i < mCallbacks.size(); i++) {
@@ -924,7 +985,9 @@
         }
         // Don't send cancel if authentication succeeds
         mFaceCancelSignal = null;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        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) {
@@ -1013,14 +1076,16 @@
         @Override
         public void run() {
             mLogger.logRetryingAfterFaceHwUnavailable(mHardwareFaceUnavailableRetryCount);
-            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_TRIGGERED_RETRY_AFTER_HW_UNAVAILABLE);
         }
     };
 
     private void onFaceCancelNotReceived() {
         mLogger.e("Face cancellation not received, transitioning to STOPPED");
         mFaceRunningState = BIOMETRIC_STATE_STOPPED;
-        KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP);
+        KeyguardUpdateMonitor.this.updateFaceListeningState(BIOMETRIC_ACTION_STOP,
+                FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED);
     }
 
     private void handleFaceError(int msgId, final String originalErrMsg) {
@@ -1043,7 +1108,8 @@
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
-            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_TRIGGERED_DURING_CANCELLATION);
         } else {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -1089,7 +1155,8 @@
         final boolean changed = (mFaceLockedOutPermanent != wasLockoutPermanent);
 
         mHandler.postDelayed(() -> {
-            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET);
         }, getBiometricLockoutDelay());
 
         if (changed) {
@@ -1334,7 +1401,8 @@
     @VisibleForTesting
     void setAssistantVisible(boolean assistantVisible) {
         mAssistantVisible = assistantVisible;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_UPDATED_ASSISTANT_VISIBILITY_CHANGED);
         if (mAssistantVisible) {
             requestActiveUnlock(
                     ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.ASSISTANT,
@@ -1512,7 +1580,7 @@
                 @Override
                 public void onUdfpsPointerDown(int sensorId) {
                     mLogger.logUdfpsPointerDown(sensorId);
-                    requestFaceAuth(true);
+                    requestFaceAuth(true, FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
                 }
 
                 /**
@@ -1696,7 +1764,7 @@
     protected void handleStartedWakingUp() {
         Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
         Assert.isMainThread();
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_STARTED_WAKING_UP);
         requestActiveUnlock(ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE, "wakingUp");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1717,7 +1785,7 @@
             }
         }
         mGoingToSleep = true;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_GOING_TO_SLEEP);
     }
 
     protected void handleFinishedGoingToSleep(int arg1) {
@@ -1730,7 +1798,8 @@
             }
         }
         // This is set specifically to stop face authentication from running.
-        updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+        updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
+                FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP);
     }
 
     private void handleScreenTurnedOff() {
@@ -1750,9 +1819,10 @@
         }
         if (mIsDreaming) {
             updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
-            updateFaceListeningState(BIOMETRIC_ACTION_STOP);
+            updateFaceListeningState(BIOMETRIC_ACTION_STOP, FACE_AUTH_STOPPED_DREAM_STARTED);
         } else {
-            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_TRIGGERED_DREAM_STOPPED);
         }
     }
 
@@ -1817,8 +1887,11 @@
             InteractionJankMonitor interactionJankMonitor,
             LatencyTracker latencyTracker,
             ActiveUnlockConfig activeUnlockConfiguration,
-            KeyguardUpdateMonitorLogger logger) {
-        mLogger = logger;
+            KeyguardUpdateMonitorLogger logger,
+            UiEventLogger uiEventLogger,
+            // This has to be a provider because SessionTracker depends on KeyguardUpdateMonitor :(
+            Provider<SessionTracker> sessionTrackerProvider,
+            PowerManager powerManager) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
         mTelephonyListenerManager = telephonyListenerManager;
@@ -1836,7 +1909,13 @@
         dumpManager.registerDumpable(getClass().getName(), this);
         mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
         mActiveUnlockConfig = activeUnlockConfiguration;
+        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);
 
         mHandler = new Handler(mainLooper) {
             @Override
@@ -1919,7 +1998,8 @@
                         setAssistantVisible((boolean) msg.obj);
                         break;
                     case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
-                        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+                        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                                FACE_AUTH_UPDATED_FP_AUTHENTICATED);
                         break;
                     case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
                         updateLogoutEnabled();
@@ -2022,15 +2102,17 @@
             @Override
             public void onAllAuthenticatorsRegistered(
                     @BiometricAuthenticator.Modality int modality) {
-                mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
+                mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                        FACE_AUTH_TRIGGERED_ALL_AUTHENTICATORS_REGISTERED));
             }
 
             @Override
             public void onEnrollmentsChanged(@BiometricAuthenticator.Modality int modality) {
-                mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
+                mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                        FACE_AUTH_TRIGGERED_ENROLLMENTS_CHANGED));
             }
         });
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT);
         if (mFpm != null) {
             mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
         }
@@ -2142,9 +2224,10 @@
         mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
     }
 
-    private void updateBiometricListeningState(int action) {
+    private void updateBiometricListeningState(int action,
+            @NonNull FaceAuthUiEvent faceAuthUiEvent) {
         updateFingerprintListeningState(action);
-        updateFaceListeningState(action);
+        updateFaceListeningState(action, faceAuthUiEvent);
     }
 
     private void updateFingerprintListeningState(int action) {
@@ -2200,7 +2283,8 @@
             return;
         }
         mAuthInterruptActive = active;
-        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_TRIGGERED_ON_REACH_GESTURE_ON_AOD);
         requestActiveUnlock(ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE, "onReach");
     }
 
@@ -2208,25 +2292,27 @@
      * Requests face authentication if we're on a state where it's allowed.
      * This will re-trigger auth in case it fails.
      * @param userInitiatedRequest true if the user explicitly requested face auth
+     * @param reason One of the reasons {@link FaceAuthApiRequestReason} on why this API is being
+     * invoked.
      */
-    public void requestFaceAuth(boolean userInitiatedRequest) {
+    public void requestFaceAuth(boolean userInitiatedRequest,
+            @FaceAuthApiRequestReason String reason) {
         mLogger.logFaceAuthRequested(userInitiatedRequest);
-        mIsFaceAuthUserRequested |= userInitiatedRequest;
-        updateFaceListeningState(BIOMETRIC_ACTION_START);
+        updateFaceListeningState(BIOMETRIC_ACTION_START, apiRequestReasonToUiEvent(reason));
     }
 
     /**
      * In case face auth is running, cancel it.
      */
     public void cancelFaceAuth() {
-        stopListeningForFace();
+        stopListeningForFace(FACE_AUTH_STOPPED_USER_INPUT_ON_BOUNCER);
     }
 
     public boolean isFaceScanning() {
         return mFaceRunningState == BIOMETRIC_STATE_RUNNING;
     }
 
-    private void updateFaceListeningState(int action) {
+    private void updateFaceListeningState(int action, @NonNull FaceAuthUiEvent faceAuthUiEvent) {
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
         if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
@@ -2239,17 +2325,21 @@
                 mLogger.v("Ignoring stopListeningForFace()");
                 return;
             }
-            mIsFaceAuthUserRequested = false;
-            stopListeningForFace();
+            stopListeningForFace(faceAuthUiEvent);
         } else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
             if (action == BIOMETRIC_ACTION_STOP) {
                 mLogger.v("Ignoring startListeningForFace()");
                 return;
             }
-            startListeningForFace();
+            startListeningForFace(faceAuthUiEvent);
         }
     }
 
+    @Nullable
+    private InstanceId getKeyguardSessionId() {
+        return mSessionTrackerProvider.get().getSessionId(SESSION_KEYGUARD);
+    }
+
     /**
      * Initiates active unlock to get the unlock token ready.
      */
@@ -2318,7 +2408,8 @@
     public void setUdfpsBouncerShowing(boolean showing) {
         mUdfpsBouncerShowing = showing;
         if (mUdfpsBouncerShowing) {
-            updateFaceListeningState(BIOMETRIC_ACTION_START);
+            updateFaceListeningState(BIOMETRIC_ACTION_START,
+                    FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN);
             requestActiveUnlock(
                     ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT,
                     "udfpsBouncer");
@@ -2480,7 +2571,7 @@
         // on bouncer if both fp and fingerprint are enrolled.
         final boolean awakeKeyguardExcludingBouncerShowing = mKeyguardIsVisible
                 && mDeviceInteractive && !mGoingToSleep
-                && !statusBarShadeLocked && !mBouncerFullyShown;
+                && !statusBarShadeLocked && !mBouncerIsOrWillBeShowing;
         final int user = getCurrentUser();
         final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
         final boolean isLockDown =
@@ -2549,6 +2640,7 @@
                     becauseCannotSkipBouncer,
                     biometricEnabledForUser,
                     mBouncerFullyShown,
+                    mBouncerIsOrWillBeShowing,
                     faceAuthenticated,
                     faceDisabledForUser,
                     mGoingToSleep,
@@ -2630,7 +2722,7 @@
         }
     }
 
-    private void startListeningForFace() {
+    private void startListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) {
         final int userId = getCurrentUser();
         final boolean unlockPossible = isUnlockWithFacePossible(userId);
         if (mFaceCancelSignal != null) {
@@ -2644,7 +2736,8 @@
             // Waiting for ERROR_CANCELED before requesting auth again
             return;
         }
-        mLogger.logStartedListeningForFace(mFaceRunningState);
+        mLogger.logStartedListeningForFace(mFaceRunningState, faceAuthUiEvent.getReason());
+        mUiEventLogger.log(faceAuthUiEvent, getKeyguardSessionId());
 
         if (unlockPossible) {
             mFaceCancelSignal = new CancellationSignal();
@@ -2728,8 +2821,10 @@
         }
     }
 
-    private void stopListeningForFace() {
+    private void stopListeningForFace(@NonNull FaceAuthUiEvent faceAuthUiEvent) {
         mLogger.v("stopListeningForFace()");
+        mLogger.logStoppedListeningForFace(mFaceRunningState, faceAuthUiEvent.getReason());
+        mUiEventLogger.log(faceAuthUiEvent, getKeyguardSessionId());
         if (mFaceRunningState == BIOMETRIC_STATE_RUNNING) {
             if (mFaceCancelSignal != null) {
                 mFaceCancelSignal.cancel();
@@ -3058,7 +3153,8 @@
                 cb.onKeyguardVisibilityChangedRaw(showing);
             }
         }
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED);
     }
 
     /**
@@ -3066,7 +3162,8 @@
      */
     private void handleKeyguardReset() {
         mLogger.d("handleKeyguardReset");
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_UPDATED_KEYGUARD_RESET);
         mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
     }
 
@@ -3117,7 +3214,8 @@
                     cb.onKeyguardBouncerStateChanged(mBouncerIsOrWillBeShowing);
                 }
             }
-            updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN);
         }
 
         if (wasBouncerFullyShown != mBouncerFullyShown) {
@@ -3132,7 +3230,8 @@
                     cb.onKeyguardBouncerFullyShowingChanged(mBouncerFullyShown);
                 }
             }
-            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN);
         }
     }
 
@@ -3260,7 +3359,8 @@
         mSwitchingUser = switching;
         // Since this comes in on a binder thread, we need to post if first
         mHandler.post(() -> {
-            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_UPDATED_USER_SWITCHING);
         });
     }
 
@@ -3352,6 +3452,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();
@@ -3601,6 +3702,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/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index fdde402..0a82968 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
-import android.graphics.PointF;
+import android.graphics.Point;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -54,7 +54,7 @@
     private boolean mAod;
 
     @NonNull private final RectF mSensorRect;
-    @NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
+    @NonNull private Point mLockIconCenter = new Point(0, 0);
     private float mRadius;
     private int mLockIconPadding;
 
@@ -126,7 +126,7 @@
      * Set the location of the lock icon.
      */
     @VisibleForTesting
-    public void setCenterLocation(@NonNull PointF center, float radius, int drawablePadding) {
+    public void setCenterLocation(@NonNull Point center, float radius, int drawablePadding) {
         mLockIconCenter = center;
         mRadius = radius;
         mLockIconPadding = drawablePadding;
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index d6974df..a6b8841 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -27,7 +27,7 @@
 
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.PointF;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedStateListDrawable;
 import android.hardware.biometrics.BiometricAuthenticator;
@@ -359,8 +359,9 @@
                     mAuthController.getUdfpsRadius(), scaledPadding);
         } else {
             mView.setCenterLocation(
-                    new PointF(mWidthPixels / 2,
-                        mHeightPixels - ((mBottomPaddingPx + sLockIconRadiusPx) * scaleFactor)),
+                    new Point((int) mWidthPixels / 2,
+                            (int) (mHeightPixels
+                                    - ((mBottomPaddingPx + sLockIconRadiusPx) * scaleFactor))),
                         sLockIconRadiusPx * scaleFactor, scaledPadding);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
similarity index 74%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
index 88e227b..f449edf 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package com.android.keyguard
 
-import javax.inject.Qualifier
-
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+/** 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..e0cafae 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.8f + mHeight * 0.2 * 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/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 6c452bd..7a00cd9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -45,7 +45,7 @@
 
     fun e(@CompileTimeConstant msg: String) = log(msg, ERROR)
 
-    fun v(@CompileTimeConstant msg: String) = log(msg, VERBOSE)
+    fun v(@CompileTimeConstant msg: String) = log(msg, ERROR)
 
     fun w(@CompileTimeConstant msg: String) = log(msg, WARNING)
 
@@ -262,10 +262,18 @@
         logBuffer.log(TAG, VERBOSE, { int1 = subId }, { "reportSimUnlocked(subId=$int1)" })
     }
 
-    fun logStartedListeningForFace(faceRunningState: Int) {
-        logBuffer.log(TAG, VERBOSE,
-                { int1 = faceRunningState },
-                { "startListeningForFace(): $int1" })
+    fun logStartedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
+        logBuffer.log(TAG, VERBOSE, {
+            int1 = faceRunningState
+            str1 = faceAuthReason
+        }, { "startListeningForFace(): $int1, reason: $str1" })
+    }
+
+    fun logStoppedListeningForFace(faceRunningState: Int, faceAuthReason: String) {
+        logBuffer.log(TAG, VERBOSE, {
+            int1 = faceRunningState
+            str1 = faceAuthReason
+        }, { "stopListeningForFace(): currentFaceRunningState: $int1, reason: $str1" })
     }
 
     fun logSubInfo(subInfo: SubscriptionInfo?) {
@@ -332,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/keyguard/logging/KeyguardViewMediatorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardViewMediatorLogger.kt
deleted file mode 100644
index f54bf02..0000000
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardViewMediatorLogger.kt
+++ /dev/null
@@ -1,690 +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.keyguard.logging
-
-import android.os.RemoteException
-import android.view.WindowManagerPolicyConstants
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.ERROR
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
-import com.android.systemui.log.LogLevel.WTF
-import com.android.systemui.log.dagger.KeyguardViewMediatorLog
-import javax.inject.Inject
-
-private const val TAG = "KeyguardViewMediatorLog"
-
-@SysUISingleton
-class KeyguardViewMediatorLogger @Inject constructor(
-        @KeyguardViewMediatorLog private val logBuffer: LogBuffer,
-) {
-
-    fun logFailedLoadLockSound(soundPath: String) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                { str1 = soundPath },
-                { "failed to load lock sound from $str1" }
-        )
-    }
-
-    fun logFailedLoadUnlockSound(soundPath: String) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                { str1 = soundPath },
-                { "failed to load unlock sound from $str1" }
-        )
-    }
-
-    fun logFailedLoadTrustedSound(soundPath: String) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                { str1 = soundPath },
-                { "failed to load trusted sound from $str1" }
-        )
-    }
-
-    fun logOnSystemReady() {
-        logBuffer.log(TAG, DEBUG, "onSystemReady")
-    }
-
-    fun logOnStartedGoingToSleep(offReason: Int) {
-        val offReasonString = WindowManagerPolicyConstants.offReasonToString(offReason)
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { str1 = offReasonString },
-                { "onStartedGoingToSleep($str1)" }
-        )
-    }
-
-    fun logPendingExitSecureCallbackCancelled() {
-        logBuffer.log(TAG, DEBUG, "pending exit secure callback cancelled")
-    }
-
-    fun logFailedOnKeyguardExitResultFalse(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onKeyguardExitResult(false)",
-                remoteException
-        )
-    }
-
-    fun logOnFinishedGoingToSleep(offReason: Int) {
-        val offReasonString = WindowManagerPolicyConstants.offReasonToString(offReason)
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { str1 = offReasonString },
-                { "onFinishedGoingToSleep($str1)" }
-        )
-    }
-
-    fun logPinLockRequestedStartingKeyguard() {
-        logBuffer.log(TAG, INFO, "PIN lock requested, starting keyguard")
-    }
-
-    fun logUserSwitching(userId: Int) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { int1 = userId },
-                { "onUserSwitching $int1" }
-        )
-    }
-
-    fun logOnUserSwitchComplete(userId: Int) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { int1 = userId },
-                { "onUserSwitchComplete $int1" }
-        )
-    }
-
-    fun logOnSimStateChanged(subId: Int, slotId: Int, simState: String) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    int1 = subId
-                    int2 = slotId
-                    str1 = simState
-                },
-                { "onSimStateChanged(subId=$int1, slotId=$int2, state=$str1)" }
-        )
-    }
-
-    fun logFailedToCallOnSimSecureStateChanged(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onSimSecureStateChanged",
-                remoteException
-        )
-    }
-
-    fun logIccAbsentIsNotShowing() {
-        logBuffer.log(TAG, DEBUG, "ICC_ABSENT isn't showing, we need to show the " +
-                "keyguard since the device isn't provisioned yet.")
-    }
-
-    fun logSimMovedToAbsent() {
-        logBuffer.log(TAG, DEBUG, "SIM moved to ABSENT when the " +
-                "previous state was locked. Reset the state.")
-    }
-
-    fun logIntentValueIccLocked() {
-        logBuffer.log(TAG, DEBUG, "INTENT_VALUE_ICC_LOCKED and keyguard isn't " +
-                "showing; need to show keyguard so user can enter sim pin")
-    }
-
-    fun logPermDisabledKeyguardNotShowing() {
-        logBuffer.log(TAG, DEBUG, "PERM_DISABLED and keyguard isn't showing.")
-    }
-
-    fun logPermDisabledResetStateLocked() {
-        logBuffer.log(TAG, DEBUG, "PERM_DISABLED, resetStateLocked to show permanently " +
-                "disabled message in lockscreen.")
-    }
-
-    fun logReadyResetState(showing: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = showing },
-                { "READY, reset state? $bool1"}
-        )
-    }
-
-    fun logSimMovedToReady() {
-        logBuffer.log(TAG, DEBUG, "SIM moved to READY when the previously was locked. " +
-                "Reset the state.")
-    }
-
-    fun logUnspecifiedSimState(simState: Int) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { int1 = simState },
-                { "Unspecific state: $int1" }
-        )
-    }
-
-    fun logOccludeLaunchAnimationCancelled(occluded: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = occluded },
-                { "Occlude launch animation cancelled. Occluded state is now: $bool1"}
-        )
-    }
-
-    fun logActivityLaunchAnimatorLaunchContainerChanged() {
-        logBuffer.log(TAG, WTF, "Someone tried to change the launch container for the " +
-                "ActivityLaunchAnimator, which should never happen.")
-    }
-
-    fun logVerifyUnlock() {
-        logBuffer.log(TAG, DEBUG, "verifyUnlock")
-    }
-
-    fun logIgnoreUnlockDeviceNotProvisioned() {
-        logBuffer.log(TAG, DEBUG, "ignoring because device isn't provisioned")
-    }
-
-    fun logFailedToCallOnKeyguardExitResultFalse(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onKeyguardExitResult(false)",
-                remoteException
-        )
-    }
-
-    fun logVerifyUnlockCalledNotExternallyDisabled() {
-        logBuffer.log(TAG, WARNING, "verifyUnlock called when not externally disabled")
-    }
-
-    fun logSetOccluded(isOccluded: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = isOccluded },
-                { "setOccluded($bool1)" }
-        )
-    }
-
-    fun logHandleSetOccluded(isOccluded: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = isOccluded },
-                { "handleSetOccluded($bool1)" }
-        )
-    }
-
-    fun logIgnoreHandleShow() {
-        logBuffer.log(TAG, DEBUG, "ignoring handleShow because system is not ready.")
-    }
-
-    fun logHandleShow() {
-        logBuffer.log(TAG, DEBUG, "handleShow")
-    }
-
-    fun logHandleHide() {
-        logBuffer.log(TAG, DEBUG, "handleHide")
-    }
-
-    fun logSplitSystemUserQuitUnlocking() {
-        logBuffer.log(TAG, DEBUG, "Split system user, quit unlocking.")
-    }
-
-    fun logHandleStartKeyguardExitAnimation(startTime: Long, fadeoutDuration: Long) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    long1 = startTime
-                    long2 = fadeoutDuration
-                },
-                { "handleStartKeyguardExitAnimation startTime=$long1 fadeoutDuration=$long2" }
-        )
-    }
-
-    fun logHandleVerifyUnlock() {
-        logBuffer.log(TAG, DEBUG, "handleVerifyUnlock")
-    }
-
-    fun logHandleNotifyStartedGoingToSleep() {
-        logBuffer.log(TAG, DEBUG, "handleNotifyStartedGoingToSleep")
-    }
-
-    fun logHandleNotifyFinishedGoingToSleep() {
-        logBuffer.log(TAG, DEBUG, "handleNotifyFinishedGoingToSleep")
-    }
-
-    fun logHandleNotifyWakingUp() {
-        logBuffer.log(TAG, DEBUG, "handleNotifyWakingUp")
-    }
-
-    fun logHandleReset() {
-        logBuffer.log(TAG, DEBUG, "handleReset")
-    }
-
-    fun logKeyguardDone() {
-        logBuffer.log(TAG, DEBUG, "keyguardDone")
-    }
-
-    fun logKeyguardDonePending() {
-        logBuffer.log(TAG, DEBUG, "keyguardDonePending")
-    }
-
-    fun logKeyguardGone() {
-        logBuffer.log(TAG, DEBUG, "keyguardGone")
-    }
-
-    fun logUnoccludeAnimationCancelled(isOccluded: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = isOccluded },
-                { "Unocclude animation cancelled. Occluded state is now: $bool1" }
-        )
-    }
-
-    fun logShowLocked() {
-        logBuffer.log(TAG, DEBUG, "showLocked")
-    }
-
-    fun logHideLocked() {
-        logBuffer.log(TAG, DEBUG, "hideLocked")
-    }
-
-    fun logResetStateLocked() {
-        logBuffer.log(TAG, DEBUG, "resetStateLocked")
-    }
-
-    fun logNotifyStartedGoingToSleep() {
-        logBuffer.log(TAG, DEBUG, "notifyStartedGoingToSleep")
-    }
-
-    fun logNotifyFinishedGoingToSleep() {
-        logBuffer.log(TAG, DEBUG, "notifyFinishedGoingToSleep")
-    }
-
-    fun logNotifyStartedWakingUp() {
-        logBuffer.log(TAG, DEBUG, "notifyStartedWakingUp")
-    }
-
-    fun logDoKeyguardShowingLockScreen() {
-        logBuffer.log(TAG, DEBUG, "doKeyguard: showing the lock screen")
-    }
-
-    fun logDoKeyguardNotShowingLockScreenOff() {
-        logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because lockscreen is off")
-    }
-
-    fun logDoKeyguardNotShowingDeviceNotProvisioned() {
-        logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because device isn't " +
-                "provisioned and the sim is not locked or missing")
-    }
-
-    fun logDoKeyguardNotShowingAlreadyShowing() {
-        logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because it is already showing")
-    }
-
-    fun logDoKeyguardNotShowingBootingCryptkeeper() {
-        logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because booting to cryptkeeper")
-    }
-
-    fun logDoKeyguardNotShowingExternallyDisabled() {
-        logBuffer.log(TAG, DEBUG, "doKeyguard: not showing because externally disabled")
-    }
-
-    fun logFailedToCallOnDeviceProvisioned(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onDeviceProvisioned",
-                remoteException
-        )
-    }
-
-    fun logMaybeHandlePendingLockNotHandling() {
-        logBuffer.log(TAG, DEBUG, "#maybeHandlePendingLock: not handling because the " +
-                "screen off animation's isKeyguardShowDelayed() returned true. This should be " +
-                "handled soon by #onStartedWakingUp, or by the end actions of the " +
-                "screen off animation.")
-    }
-
-    fun logMaybeHandlePendingLockKeyguardGoingAway() {
-        logBuffer.log(TAG, DEBUG, "#maybeHandlePendingLock: not handling because the " +
-                "keyguard is going away. This should be handled shortly by " +
-                "StatusBar#finishKeyguardFadingAway.")
-    }
-
-    fun logMaybeHandlePendingLockHandling() {
-        logBuffer.log(TAG, DEBUG, "#maybeHandlePendingLock: handling pending lock; " +
-                "locking keyguard.")
-    }
-
-    fun logSetAlarmToTurnOffKeyguard(delayedShowingSequence: Int) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { int1 = delayedShowingSequence },
-                { "setting alarm to turn off keyguard, seq = $int1" }
-        )
-    }
-
-    fun logOnStartedWakingUp(delayedShowingSequence: Int) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { int1 = delayedShowingSequence },
-                { "onStartedWakingUp, seq = $int1" }
-        )
-    }
-
-    fun logSetKeyguardEnabled(enabled: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = enabled },
-                { "setKeyguardEnabled($bool1)" }
-        )
-    }
-
-    fun logIgnoreVerifyUnlockRequest() {
-        logBuffer.log(TAG, DEBUG, "in process of verifyUnlock request, ignoring")
-    }
-
-    fun logRememberToReshowLater() {
-        logBuffer.log(TAG, DEBUG, "remembering to reshow, hiding keyguard, disabling " +
-                "status bar expansion")
-    }
-
-    fun logPreviouslyHiddenReshow() {
-        logBuffer.log(TAG, DEBUG, "previously hidden, reshowing, reenabling status " +
-                "bar expansion")
-    }
-
-    fun logOnKeyguardExitResultFalseResetting() {
-        logBuffer.log(TAG, DEBUG, "onKeyguardExitResult(false), resetting")
-    }
-
-    fun logWaitingUntilKeyguardVisibleIsFalse() {
-        logBuffer.log(TAG, DEBUG, "waiting until mWaitingUntilKeyguardVisible is false")
-    }
-
-    fun logDoneWaitingUntilKeyguardVisible() {
-        logBuffer.log(TAG, DEBUG, "done waiting for mWaitingUntilKeyguardVisible")
-    }
-
-    fun logUnoccludeAnimatorOnAnimationStart() {
-        logBuffer.log(TAG, DEBUG, "UnoccludeAnimator#onAnimationStart. " +
-                "Set occluded = false.")
-    }
-
-    fun logNoAppsProvidedToUnoccludeRunner() {
-        logBuffer.log(TAG, DEBUG, "No apps provided to unocclude runner; " +
-                "skipping animation and unoccluding.")
-    }
-
-    fun logReceivedDelayedKeyguardAction(sequence: Int, delayedShowingSequence: Int) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    int1 = sequence
-                    int2 = delayedShowingSequence
-                },
-                {
-                    "received DELAYED_KEYGUARD_ACTION with seq = $int1 " +
-                            "mDelayedShowingSequence = $int2"
-                }
-        )
-    }
-
-    fun logTimeoutWhileActivityDrawn() {
-        logBuffer.log(TAG, WARNING, "Timeout while waiting for activity drawn")
-    }
-
-    fun logTryKeyguardDonePending(
-            keyguardDonePending: Boolean,
-            hideAnimationRun: Boolean,
-            hideAnimationRunning: Boolean
-    ) {
-        logBuffer.log(TAG, DEBUG,
-                {
-                    bool1 = keyguardDonePending
-                    bool2 = hideAnimationRun
-                    bool3 = hideAnimationRunning
-                },
-                { "tryKeyguardDone: pending - $bool1, animRan - $bool2 animRunning - $bool3" }
-        )
-    }
-
-    fun logTryKeyguardDonePreHideAnimation() {
-        logBuffer.log(TAG, DEBUG, "tryKeyguardDone: starting pre-hide animation")
-    }
-
-    fun logHandleKeyguardDone() {
-        logBuffer.log(TAG, DEBUG, "handleKeyguardDone")
-    }
-
-    fun logDeviceGoingToSleep() {
-        logBuffer.log(TAG, INFO, "Device is going to sleep, aborting keyguardDone")
-    }
-
-    fun logFailedToCallOnKeyguardExitResultTrue(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onKeyguardExitResult(true)",
-                remoteException
-        )
-    }
-
-    fun logHandleKeyguardDoneDrawing() {
-        logBuffer.log(TAG, DEBUG, "handleKeyguardDoneDrawing")
-    }
-
-    fun logHandleKeyguardDoneDrawingNotifyingKeyguardVisible() {
-        logBuffer.log(TAG, DEBUG, "handleKeyguardDoneDrawing: notifying " +
-                "mWaitingUntilKeyguardVisible")
-    }
-
-    fun logUpdateActivityLockScreenState(showing: Boolean, aodShowing: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    bool1 = showing
-                    bool2 = aodShowing
-                },
-                { "updateActivityLockScreenState($bool1, $bool2)" }
-        )
-    }
-
-    fun logFailedToCallSetLockScreenShown(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call setLockScreenShown",
-                remoteException
-        )
-    }
-
-    fun logKeyguardGoingAway() {
-        logBuffer.log(TAG, DEBUG, "keyguardGoingAway")
-    }
-
-    fun logFailedToCallKeyguardGoingAway(keyguardFlag: Int, remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                ERROR,
-                { int1 = keyguardFlag },
-                { "Failed to call keyguardGoingAway($int1)" },
-                remoteException
-        )
-    }
-
-    fun logHideAnimationFinishedRunnable() {
-        logBuffer.log(TAG, WARNING, "mHideAnimationFinishedRunnable#run")
-    }
-
-    fun logFailedToCallOnAnimationFinished(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onAnimationFinished",
-                remoteException
-        )
-    }
-
-    fun logFailedToCallOnAnimationStart(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onAnimationStart",
-                remoteException
-        )
-    }
-
-    fun logOnKeyguardExitRemoteAnimationFinished() {
-        logBuffer.log(TAG, DEBUG, "onKeyguardExitRemoteAnimationFinished")
-    }
-
-    fun logSkipOnKeyguardExitRemoteAnimationFinished(
-            cancelled: Boolean,
-            surfaceBehindRemoteAnimationRunning: Boolean,
-            surfaceBehindRemoteAnimationRequested: Boolean
-    ) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    bool1 = cancelled
-                    bool2 = surfaceBehindRemoteAnimationRunning
-                    bool3 = surfaceBehindRemoteAnimationRequested
-                },
-                {
-                    "skip onKeyguardExitRemoteAnimationFinished cancelled=$bool1 " +
-                            "surfaceAnimationRunning=$bool2 " +
-                            "surfaceAnimationRequested=$bool3"
-                }
-        )
-    }
-
-    fun logOnKeyguardExitRemoteAnimationFinishedHideKeyguardView() {
-        logBuffer.log(TAG, DEBUG, "onKeyguardExitRemoteAnimationFinished" +
-                "#hideKeyguardViewAfterRemoteAnimation")
-    }
-
-    fun logSkipHideKeyguardViewAfterRemoteAnimation(
-            dismissingFromSwipe: Boolean,
-            wasShowing: Boolean
-    ) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    bool1 = dismissingFromSwipe
-                    bool2 = wasShowing
-                },
-                {
-                    "skip hideKeyguardViewAfterRemoteAnimation dismissFromSwipe=$bool1 " +
-                            "wasShowing=$bool2"
-                }
-        )
-    }
-
-    fun logCouldNotGetStatusBarManager() {
-        logBuffer.log(TAG, WARNING, "Could not get status bar manager")
-    }
-
-    fun logAdjustStatusBarLocked(
-            showing: Boolean,
-            occluded: Boolean,
-            secure: Boolean,
-            forceHideHomeRecentsButtons: Boolean,
-            flags: String
-    ) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                {
-                    bool1 = showing
-                    bool2 = occluded
-                    bool3 = secure
-                    bool4 = forceHideHomeRecentsButtons
-                    str3 = flags
-                },
-                {
-                    "adjustStatusBarLocked: mShowing=$bool1 mOccluded=$bool2 isSecure=$bool3 " +
-                            "force=$bool4 --> flags=0x$str3"
-                }
-        )
-    }
-
-    fun logFailedToCallOnShowingStateChanged(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call onShowingStateChanged",
-                remoteException
-        )
-    }
-
-    fun logFailedToCallNotifyTrustedChangedLocked(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call notifyTrustedChangedLocked",
-                remoteException
-        )
-    }
-
-    fun logFailedToCallIKeyguardStateCallback(remoteException: RemoteException) {
-        logBuffer.log(
-                TAG,
-                WARNING,
-                "Failed to call to IKeyguardStateCallback",
-                remoteException
-        )
-    }
-
-    fun logOccludeAnimatorOnAnimationStart() {
-        logBuffer.log(TAG, DEBUG, "OccludeAnimator#onAnimationStart. Set occluded = true.")
-    }
-
-    fun logOccludeAnimationCancelledByWm(isKeyguardOccluded: Boolean) {
-        logBuffer.log(
-                TAG,
-                DEBUG,
-                { bool1 = isKeyguardOccluded },
-                { "Occlude animation cancelled by WM. Setting occluded state to: $bool1" }
-        )
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt b/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt
new file mode 100644
index 0000000..109be40
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ChooserSelector.kt
@@ -0,0 +1,67 @@
+package com.android.systemui
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.FlagListenable
+import com.android.systemui.flags.Flags
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
+
+@SysUISingleton
+class ChooserSelector @Inject constructor(
+        context: Context,
+        private val featureFlags: FeatureFlags,
+        @Application private val coroutineScope: CoroutineScope,
+        @Background private val bgDispatcher: CoroutineDispatcher
+) : CoreStartable(context) {
+
+    private val packageManager = context.packageManager
+    private val chooserComponent = ComponentName.unflattenFromString(
+            context.resources.getString(ChooserSelectorResourceHelper.CONFIG_CHOOSER_ACTIVITY))
+
+    override fun start() {
+        coroutineScope.launch {
+            val listener = FlagListenable.Listener { event ->
+                if (event.flagId == Flags.CHOOSER_UNBUNDLED.id) {
+                    launch { updateUnbundledChooserEnabled() }
+                    event.requestNoRestart()
+                }
+            }
+            featureFlags.addListener(Flags.CHOOSER_UNBUNDLED, listener)
+            updateUnbundledChooserEnabled()
+
+            awaitCancellationAndThen { featureFlags.removeListener(listener) }
+        }
+    }
+
+    private suspend fun updateUnbundledChooserEnabled() {
+        setUnbundledChooserEnabled(withContext(bgDispatcher) {
+            featureFlags.isEnabled(Flags.CHOOSER_UNBUNDLED)
+        })
+    }
+
+    private fun setUnbundledChooserEnabled(enabled: Boolean) {
+        val newState = if (enabled) {
+            PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+        } else {
+            PackageManager.COMPONENT_ENABLED_STATE_DISABLED
+        }
+        packageManager.setComponentEnabledSetting(chooserComponent, newState, /* flags = */ 0)
+    }
+
+    suspend inline fun awaitCancellation(): Nothing = suspendCancellableCoroutine { }
+    suspend inline fun awaitCancellationAndThen(block: () -> Unit): Nothing = try {
+        awaitCancellation()
+    } finally {
+        block()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java
index 88e227b..7a2de7b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/ChooserSelectorResourceHelper.java
@@ -14,10 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package com.android.systemui;
 
-import javax.inject.Qualifier
+import androidx.annotation.StringRes;
 
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+import com.android.internal.R;
+
+/** Helper class for referencing resources */
+class ChooserSelectorResourceHelper {
+
+    private ChooserSelectorResourceHelper() {
+    }
+
+    @StringRes
+    static final int CONFIG_CHOOSER_ACTIVITY = R.string.config_chooserActivity;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 614a87f..7fc8123 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -85,10 +85,6 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -303,7 +299,6 @@
     @Inject Lazy<IStatusBarService> mIStatusBarService;
     @Inject Lazy<DisplayMetrics> mDisplayMetrics;
     @Inject Lazy<LockscreenGestureLogger> mLockscreenGestureLogger;
-    @Inject Lazy<KeyguardEnvironment> mKeyguardEnvironment;
     @Inject Lazy<ShadeController> mShadeController;
     @Inject Lazy<NotificationRemoteInputManager.Callback> mNotificationRemoteInputManagerCallback;
     @Inject Lazy<AppOpsController> mAppOpsController;
@@ -311,8 +306,6 @@
     @Inject Lazy<AccessibilityFloatingMenuController> mAccessibilityFloatingMenuController;
     @Inject Lazy<StatusBarStateController> mStatusBarStateController;
     @Inject Lazy<NotificationLockscreenUserManager> mNotificationLockscreenUserManager;
-    @Inject Lazy<NotificationGroupManagerLegacy> mNotificationGroupManager;
-    @Inject Lazy<VisualStabilityManager> mVisualStabilityManager;
     @Inject Lazy<NotificationGutsManager> mNotificationGutsManager;
     @Inject Lazy<NotificationMediaManager> mNotificationMediaManager;
     @Inject Lazy<NotificationRemoteInputManager> mNotificationRemoteInputManager;
@@ -322,10 +315,8 @@
     @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
     @Inject Lazy<SmartReplyController> mSmartReplyController;
     @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
-    @Inject Lazy<NotificationEntryManager> mNotificationEntryManager;
     @Inject Lazy<SensorPrivacyManager> mSensorPrivacyManager;
     @Inject Lazy<AutoHideController> mAutoHideController;
-    @Inject Lazy<ForegroundServiceNotificationListener> mForegroundServiceNotificationListener;
     @Inject Lazy<PrivacyItemController> mPrivacyItemController;
     @Inject @Background Lazy<Looper> mBgLooper;
     @Inject @Background Lazy<Handler> mBgHandler;
@@ -507,7 +498,6 @@
 
         mProviders.put(LockscreenGestureLogger.class, mLockscreenGestureLogger::get);
 
-        mProviders.put(KeyguardEnvironment.class, mKeyguardEnvironment::get);
         mProviders.put(ShadeController.class, mShadeController::get);
 
         mProviders.put(NotificationRemoteInputManager.Callback.class,
@@ -523,8 +513,6 @@
         mProviders.put(StatusBarStateController.class, mStatusBarStateController::get);
         mProviders.put(NotificationLockscreenUserManager.class,
                 mNotificationLockscreenUserManager::get);
-        mProviders.put(VisualStabilityManager.class, mVisualStabilityManager::get);
-        mProviders.put(NotificationGroupManagerLegacy.class, mNotificationGroupManager::get);
         mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
         mProviders.put(NotificationGutsManager.class, mNotificationGutsManager::get);
         mProviders.put(NotificationRemoteInputManager.class,
@@ -536,9 +524,6 @@
         mProviders.put(SmartReplyController.class, mSmartReplyController::get);
         mProviders.put(RemoteInputQuickSettingsDisabler.class,
                 mRemoteInputQuickSettingsDisabler::get);
-        mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get);
-        mProviders.put(ForegroundServiceNotificationListener.class,
-                mForegroundServiceNotificationListener::get);
         mProviders.put(ClockManager.class, mClockManager::get);
         mProviders.put(PrivacyItemController.class, mPrivacyItemController::get);
         mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get);
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index 04e26d3..a1a3b72 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -23,14 +23,10 @@
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 
-import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.util.time.SystemClock;
 
 import javax.inject.Inject;
 
@@ -43,42 +39,20 @@
 
     private final Context mContext;
     private final ForegroundServiceController mForegroundServiceController;
-    private final NotificationEntryManager mEntryManager;
+    private final NotifPipeline mNotifPipeline;
 
     @Inject
     public ForegroundServiceNotificationListener(Context context,
             ForegroundServiceController foregroundServiceController,
-            NotificationEntryManager notificationEntryManager,
-            NotifPipeline notifPipeline,
-            SystemClock systemClock) {
+            NotifPipeline notifPipeline) {
         mContext = context;
         mForegroundServiceController = foregroundServiceController;
+        mNotifPipeline = notifPipeline;
+    }
 
-        // TODO: (b/145659174) remove mEntryManager when moving to NewNotifPipeline. Replaced by
-        //  ForegroundCoordinator
-        mEntryManager = notificationEntryManager;
-        mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
-            @Override
-            public void onPendingEntryAdded(NotificationEntry entry) {
-                addNotification(entry, entry.getImportance());
-            }
-
-            @Override
-            public void onPreEntryUpdated(NotificationEntry entry) {
-                updateNotification(entry, entry.getImportance());
-            }
-
-            @Override
-            public void onEntryRemoved(
-                    NotificationEntry entry,
-                    NotificationVisibility visibility,
-                    boolean removedByUser,
-                    int reason) {
-                removeNotification(entry.getSbn());
-            }
-        });
-
-        notifPipeline.addCollectionListener(new NotifCollectionListener() {
+    /** Initializes this listener by connecting it to the notification pipeline. */
+    public void init() {
+        mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
             @Override
             public void onEntryAdded(NotificationEntry entry) {
                 addNotification(entry, entry.getImportance());
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4c400a8..2e13903 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -72,6 +72,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.decor.CutoutDecorProviderFactory;
 import com.android.systemui.decor.DecorProvider;
 import com.android.systemui.decor.DecorProviderFactory;
 import com.android.systemui.decor.DecorProviderKt;
@@ -118,6 +119,13 @@
     private static final boolean VERBOSE = false;
     static final boolean DEBUG_COLOR = DEBUG_SCREENSHOT_ROUNDED_CORNERS;
 
+    private static final int[] DISPLAY_CUTOUT_IDS = {
+            R.id.display_cutout,
+            R.id.display_cutout_left,
+            R.id.display_cutout_right,
+            R.id.display_cutout_bottom
+    };
+
     private DisplayManager mDisplayManager;
     @VisibleForTesting
     protected boolean mIsRegistered;
@@ -139,13 +147,11 @@
     protected RoundedCornerResDelegate mRoundedCornerResDelegate;
     @VisibleForTesting
     protected DecorProviderFactory mRoundedCornerFactory;
+    private CutoutDecorProviderFactory mCutoutFactory;
     private int mProviderRefreshToken = 0;
     @VisibleForTesting
     protected OverlayWindow[] mOverlays = null;
     @VisibleForTesting
-    @Nullable
-    DisplayCutoutView[] mCutoutViews;
-    @VisibleForTesting
     ViewGroup mScreenDecorHwcWindow;
     @VisibleForTesting
     ScreenDecorHwcLayer mScreenDecorHwcLayer;
@@ -187,18 +193,19 @@
             return;
         }
 
-        if (mCutoutViews == null) {
-            Log.w(TAG, "DisplayCutoutView not initialized onApplyCameraProtection");
-            return;
-        }
-
-        // Show the extra protection around the front facing camera if necessary
-        for (DisplayCutoutView dcv : mCutoutViews) {
-            // Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
-            if (dcv != null) {
-                dcv.setProtection(protectionPath, bounds);
-                dcv.enableShowProtection(true);
+        int setProtectionCnt = 0;
+        for (int id: DISPLAY_CUTOUT_IDS) {
+            final View view = getOverlayView(id);
+            if (!(view instanceof DisplayCutoutView)) {
+                continue;
             }
+            ++setProtectionCnt;
+            final DisplayCutoutView dcv = (DisplayCutoutView) view;
+            dcv.setProtection(protectionPath, bounds);
+            dcv.enableShowProtection(true);
+        }
+        if (setProtectionCnt == 0) {
+            Log.e(TAG, "CutoutView not initialized showCameraProtection");
         }
     }
 
@@ -219,16 +226,17 @@
             return;
         }
 
-        if (mCutoutViews == null) {
-            Log.w(TAG, "DisplayCutoutView not initialized onHideCameraProtection");
-            return;
-        }
-        // Go back to the regular anti-aliasing
-        for (DisplayCutoutView dcv : mCutoutViews) {
-            // Check Null since not all mCutoutViews[pos] be inflated at the meanwhile
-            if (dcv != null) {
-                dcv.enableShowProtection(false);
+        int setProtectionCnt = 0;
+        for (int id: DISPLAY_CUTOUT_IDS) {
+            final View view = getOverlayView(id);
+            if (!(view instanceof DisplayCutoutView)) {
+                continue;
             }
+            ++setProtectionCnt;
+            ((DisplayCutoutView) view).enableShowProtection(false);
+        }
+        if (setProtectionCnt == 0) {
+            Log.e(TAG, "CutoutView not initialized hideCameraProtection");
         }
     }
 
@@ -335,6 +343,7 @@
         decorProviders.addAll(mFaceScanningFactory.getProviders());
         if (!hasHwLayer) {
             decorProviders.addAll(mRoundedCornerFactory.getProviders());
+            decorProviders.addAll(mCutoutFactory.getProviders());
         }
         return decorProviders;
     }
@@ -379,6 +388,7 @@
         mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
                 getPhysicalPixelDisplaySizeRatio());
         mRoundedCornerFactory = new RoundedCornerDecorProviderFactory(mRoundedCornerResDelegate);
+        mCutoutFactory = getCutoutFactory();
         mHwcScreenDecorationSupport = mContext.getDisplay().getDisplayDecorationSupport();
         updateHwLayerRoundedCornerDrawable();
         setupDecorations();
@@ -483,18 +493,13 @@
                 if (needToUpdateProviderViews) {
                     updateOverlayProviderViews(null);
                 } else {
-                    updateOverlayProviderViews(new Integer[] { mFaceScanningViewId });
-                }
-
-                if (mCutoutViews != null) {
-                    final int size = mCutoutViews.length;
-                    for (int i = 0; i < size; i++) {
-                        final DisplayCutoutView cutoutView = mCutoutViews[i];
-                        if (cutoutView == null) {
-                            continue;
-                        }
-                        cutoutView.onDisplayChanged(newUniqueId);
-                    }
+                    updateOverlayProviderViews(new Integer[] {
+                            mFaceScanningViewId,
+                            R.id.display_cutout,
+                            R.id.display_cutout_left,
+                            R.id.display_cutout_right,
+                            R.id.display_cutout_bottom,
+                    });
                 }
 
                 if (mScreenDecorHwcLayer != null) {
@@ -507,8 +512,9 @@
         updateConfiguration();
     }
 
+    @VisibleForTesting
     @Nullable
-    private View getOverlayView(@IdRes int id) {
+    View getOverlayView(@IdRes int id) {
         if (mOverlays == null) {
             return null;
         }
@@ -565,18 +571,18 @@
                 removeHwcOverlay();
             }
 
-            final DisplayCutout cutout = getCutout();
+            boolean[] hasCreatedOverlay = new boolean[BOUNDS_POSITION_LENGTH];
             final boolean shouldOptimizeVisibility = shouldOptimizeVisibility();
+            Integer bound;
+            while ((bound = DecorProviderKt.getProperBound(decorProviders)) != null) {
+                hasCreatedOverlay[bound] = true;
+                Pair<List<DecorProvider>, List<DecorProvider>> pair =
+                        DecorProviderKt.partitionAlignedBound(decorProviders, bound);
+                decorProviders = pair.getSecond();
+                createOverlay(bound, pair.getFirst(), shouldOptimizeVisibility);
+            }
             for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
-                if (shouldShowSwLayerCutout(i, cutout)
-                        || shouldShowSwLayerFaceScan(i, cutout)
-                        || shouldShowSwLayerRoundedCorner(i, cutout)
-                        || shouldShowSwLayerPrivacyDot(i, cutout)) {
-                    Pair<List<DecorProvider>, List<DecorProvider>> pair =
-                            DecorProviderKt.partitionAlignedBound(decorProviders, i);
-                    decorProviders = pair.getSecond();
-                    createOverlay(i, pair.getFirst(), shouldOptimizeVisibility);
-                } else {
+                if (!hasCreatedOverlay[i]) {
                     removeOverlay(i);
                 }
             }
@@ -639,9 +645,10 @@
         }
     }
 
-    @VisibleForTesting
-    DisplayCutout getCutout() {
-        return mContext.getDisplay().getCutout();
+    // For unit test to override
+    protected CutoutDecorProviderFactory getCutoutFactory() {
+        return new CutoutDecorProviderFactory(mContext.getResources(),
+                mContext.getDisplay());
     }
 
     @VisibleForTesting
@@ -731,16 +738,6 @@
         overlayView.setAlpha(0);
         overlayView.setForceDarkAllowed(false);
 
-        // Only show cutout in mOverlays when hwc doesn't support screen decoration
-        if (mHwcScreenDecorationSupport == null) {
-            if (mCutoutViews == null) {
-                mCutoutViews = new DisplayCutoutView[BOUNDS_POSITION_LENGTH];
-            }
-            mCutoutViews[pos] = new DisplayCutoutView(mContext, pos);
-            overlayView.addView(mCutoutViews[pos]);
-            mCutoutViews[pos].updateRotation(mRotation);
-        }
-
         mWindowManager.addView(overlayView, getWindowLayoutParams(pos));
 
         overlayView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
@@ -920,6 +917,7 @@
     }
 
     private void setupCameraListener() {
+        // TODO(b/238143614) Support dual screen camera protection
         Resources res = mContext.getResources();
         boolean enabled = res.getBoolean(R.bool.config_enableDisplayCutoutProtection);
         if (enabled) {
@@ -948,27 +946,12 @@
             mTintColor = Color.RED;
         }
 
-        if (mOverlays == null) {
-            return;
-        }
-
-        for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
-            if (mOverlays[i] == null) {
-                continue;
-            }
-            final ViewGroup overlayView = mOverlays[i].getRootView();
-            final int size = overlayView.getChildCount();
-            View child;
-            for (int j = 0; j < size; j++) {
-                child = overlayView.getChildAt(j);
-                if (child instanceof DisplayCutoutView && child.getId() == R.id.display_cutout) {
-                    ((DisplayCutoutView) child).setColor(mTintColor);
-                }
-            }
-        }
-
         updateOverlayProviderViews(new Integer[] {
                 mFaceScanningViewId,
+                R.id.display_cutout,
+                R.id.display_cutout_left,
+                R.id.display_cutout_right,
+                R.id.display_cutout_bottom,
                 R.id.rounded_corner_top_left,
                 R.id.rounded_corner_top_right,
                 R.id.rounded_corner_bottom_left,
@@ -1093,15 +1076,6 @@
                 updateHwLayerRoundedCornerDrawable();
             }
             updateLayoutParams();
-            // update cutout view rotation
-            if (mCutoutViews != null) {
-                for (final DisplayCutoutView cutoutView: mCutoutViews) {
-                    if (cutoutView == null) {
-                        continue;
-                    }
-                    cutoutView.updateRotation(mRotation);
-                }
-            }
 
             // update all provider views inside overlay
             updateOverlayProviderViews(null);
@@ -1120,46 +1094,6 @@
         return mRoundedCornerFactory.getHasProviders();
     }
 
-    private boolean isDefaultShownOverlayPos(@BoundsPosition int pos,
-            @Nullable DisplayCutout cutout) {
-        // for cutout is null or cutout with only waterfall.
-        final boolean emptyBoundsOrWaterfall = cutout == null || cutout.isBoundsEmpty();
-        // Shows rounded corner on left and right overlays only when there is no top or bottom
-        // cutout.
-        final int rotatedTop = getBoundPositionFromRotation(BOUNDS_POSITION_TOP, mRotation);
-        final int rotatedBottom = getBoundPositionFromRotation(BOUNDS_POSITION_BOTTOM, mRotation);
-        if (emptyBoundsOrWaterfall || !cutout.getBoundingRectsAll()[rotatedTop].isEmpty()
-                || !cutout.getBoundingRectsAll()[rotatedBottom].isEmpty()) {
-            return pos == BOUNDS_POSITION_TOP || pos == BOUNDS_POSITION_BOTTOM;
-        } else {
-            return pos == BOUNDS_POSITION_LEFT || pos == BOUNDS_POSITION_RIGHT;
-        }
-    }
-
-    private boolean shouldShowSwLayerRoundedCorner(@BoundsPosition int pos,
-            @Nullable DisplayCutout cutout) {
-        return hasRoundedCorners() && isDefaultShownOverlayPos(pos, cutout)
-                && mHwcScreenDecorationSupport == null;
-    }
-
-    private boolean shouldShowSwLayerPrivacyDot(@BoundsPosition int pos,
-            @Nullable DisplayCutout cutout) {
-        return isPrivacyDotEnabled() && isDefaultShownOverlayPos(pos, cutout);
-    }
-
-    private boolean shouldShowSwLayerFaceScan(@BoundsPosition int pos,
-            @Nullable DisplayCutout cutout) {
-        return mFaceScanningFactory.getHasProviders() && isDefaultShownOverlayPos(pos, cutout);
-    }
-
-    private boolean shouldShowSwLayerCutout(@BoundsPosition int pos,
-            @Nullable DisplayCutout cutout) {
-        final Rect[] bounds = cutout == null ? null : cutout.getBoundingRectsAll();
-        final int rotatedPos = getBoundPositionFromRotation(pos, mRotation);
-        return (bounds != null && !bounds[rotatedPos].isEmpty()
-                && mHwcScreenDecorationSupport == null);
-    }
-
     private boolean shouldOptimizeVisibility() {
         return (isPrivacyDotEnabled() || mFaceScanningFactory.getHasProviders())
                 && (mHwcScreenDecorationSupport != null
@@ -1168,7 +1102,7 @@
     }
 
     private boolean shouldDrawCutout() {
-        return shouldDrawCutout(mContext);
+        return mCutoutFactory.getHasProviders();
     }
 
     static boolean shouldDrawCutout(Context context) {
@@ -1284,7 +1218,6 @@
 
             paint.setColor(mColor);
             paint.setStyle(Paint.Style.FILL);
-            setId(R.id.display_cutout);
             if (DEBUG) {
                 getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
                         getWindowTitleByPos(pos) + " drawn in rot " + mRotation));
@@ -1292,6 +1225,9 @@
         }
 
         public void setColor(int color) {
+            if (color == mColor) {
+                return;
+            }
             mColor = color;
             paint.setColor(mColor);
             invalidate();
@@ -1299,6 +1235,12 @@
 
         @Override
         public void updateRotation(int rotation) {
+            // updateRotation() is called inside CutoutDecorProviderImpl::onReloadResAndMeasure()
+            // during onDisplayChanged. In order to prevent reloading cutout info in super class,
+            // check mRotation at first
+            if (rotation == mRotation) {
+                return;
+            }
             mRotation = rotation;
             super.updateRotation(rotation);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 813f4dd..b976181 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;
@@ -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..e94b1f8 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;
 
@@ -651,6 +652,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 +691,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);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 84e1c3d..436b756 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -129,6 +129,8 @@
     private final Set<Integer> mFailedModalities = new HashSet<Integer>();
 
     private final @Background DelayableExecutor mBackgroundExecutor;
+    private int mOrientation;
+    private boolean mSkipFirstLostFocus = false;
 
     // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet.
     @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason;
@@ -441,6 +443,12 @@
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
         if (!hasWindowFocus) {
+            //it's a workaround to avoid closing BP incorrectly
+            //BP gets a onWindowFocusChanged(false) and then gets a onWindowFocusChanged(true)
+            if (mSkipFirstLostFocus) {
+                mSkipFirstLostFocus = false;
+                return;
+            }
             Log.v(TAG, "Lost window focus, dismissing the dialog");
             animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
         }
@@ -450,6 +458,9 @@
     public void onAttachedToWindow() {
         super.onAttachedToWindow();
 
+        //save the first orientation
+        mOrientation = getResources().getConfiguration().orientation;
+
         mWakefulnessLifecycle.addObserver(this);
 
         if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
@@ -621,6 +632,12 @@
         if (mBiometricView != null) {
             mBiometricView.restoreState(savedState);
         }
+
+        if (savedState != null) {
+            mSkipFirstLostFocus = savedState.getBoolean(
+                    AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED);
+        }
+
         wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
     }
 
@@ -640,30 +657,50 @@
 
     @Override
     public void onAuthenticationSucceeded(@Modality int modality) {
-        mBiometricView.onAuthenticationSucceeded(modality);
+        if (mBiometricView != null) {
+            mBiometricView.onAuthenticationSucceeded(modality);
+        } else {
+            Log.e(TAG, "onAuthenticationSucceeded(): mBiometricView is null");
+        }
     }
 
     @Override
     public void onAuthenticationFailed(@Modality int modality, String failureReason) {
-        mFailedModalities.add(modality);
-        mBiometricView.onAuthenticationFailed(modality, failureReason);
+        if (mBiometricView != null) {
+            mFailedModalities.add(modality);
+            mBiometricView.onAuthenticationFailed(modality, failureReason);
+        } else {
+            Log.e(TAG, "onAuthenticationFailed(): mBiometricView is null");
+        }
     }
 
     @Override
     public void onHelp(@Modality int modality, String help) {
-        mBiometricView.onHelp(modality, help);
+        if (mBiometricView != null) {
+            mBiometricView.onHelp(modality, help);
+        } else {
+            Log.e(TAG, "onHelp(): mBiometricView is null");
+        }
     }
 
     @Override
     public void onError(@Modality int modality, String error) {
-        mBiometricView.onError(modality, error);
+        if (mBiometricView != null) {
+            mBiometricView.onError(modality, error);
+        } else {
+            Log.e(TAG, "onError(): mBiometricView is null");
+        }
     }
 
     @Override
     public void onPointerDown() {
-        if (mBiometricView.onPointerDown(mFailedModalities)) {
-            Log.d(TAG, "retrying failed modalities (pointer down)");
-            mBiometricCallback.onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN);
+        if (mBiometricView != null) {
+            if (mBiometricView.onPointerDown(mFailedModalities)) {
+                Log.d(TAG, "retrying failed modalities (pointer down)");
+                mBiometricCallback.onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN);
+            }
+        } else {
+            Log.e(TAG, "onPointerDown(): mBiometricView is null");
         }
     }
 
@@ -677,6 +714,10 @@
                 mBiometricView != null && mCredentialView == null);
         outState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, mCredentialView != null);
 
+        if (mOrientation != getResources().getConfiguration().orientation) {
+            outState.putBoolean(AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED, true);
+        }
+
         if (mBiometricView != null) {
             mBiometricView.onSaveState(outState);
         }
@@ -694,7 +735,11 @@
 
     @Override
     public void animateToCredentialUI() {
-        mBiometricView.startTransitionToCredentialUI();
+        if (mBiometricView != null) {
+            mBiometricView.startTransitionToCredentialUI();
+        } else {
+            Log.e(TAG, "animateToCredentialUI(): mBiometricView is null");
+        }
     }
 
     void animateAway(@AuthDialogCallback.DismissedReason int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 282f251..163e3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -19,6 +19,9 @@
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
 
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -31,7 +34,6 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Point;
-import android.graphics.PointF;
 import android.graphics.Rect;
 import android.hardware.SensorPrivacyManager;
 import android.hardware.biometrics.BiometricAuthenticator.Modality;
@@ -56,7 +58,9 @@
 import android.os.RemoteException;
 import android.os.UserManager;
 import android.util.Log;
+import android.util.RotationUtils;
 import android.util.SparseBooleanArray;
+import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.MotionEvent;
 import android.view.WindowManager;
@@ -74,6 +78,7 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
 
@@ -117,8 +122,14 @@
 
     @NonNull private Point mStableDisplaySize = new Point();
 
-    @Nullable private final PointF mFaceAuthSensorLocation;
-    @Nullable private PointF mFingerprintLocation;
+    private final Display mDisplay;
+    private float mScaleFactor = 1f;
+    // sensor locations without any resolution scaling nor rotation adjustments:
+    @Nullable private final Point mFaceSensorLocationDefault;
+    @Nullable private final Point mFingerprintSensorLocationDefault;
+    // cached sensor locations:
+    @Nullable private Point mFaceSensorLocation;
+    @Nullable private Point mFingerprintSensorLocation;
     @Nullable private Rect mUdfpsBounds;
     private final Set<Callback> mCallbacks = new HashSet<>();
 
@@ -148,6 +159,20 @@
     @NonNull private final LockPatternUtils mLockPatternUtils;
     @NonNull private final InteractionJankMonitor mInteractionJankMonitor;
     private final @Background DelayableExecutor mBackgroundExecutor;
+    private final DisplayInfo mCachedDisplayInfo = new DisplayInfo();
+
+
+    private final VibratorHelper mVibratorHelper;
+
+    private void vibrateSuccess(int modality) {
+        mVibratorHelper.vibrateAuthSuccess(
+                getClass().getSimpleName() + ", modality = " + modality + "BP::success");
+    }
+
+    private void vibrateError(int modality) {
+        mVibratorHelper.vibrateAuthError(
+                getClass().getSimpleName() + ", modality = " + modality + "BP::error");
+    }
 
     @VisibleForTesting
     final TaskStackListener mTaskStackListener = new TaskStackListener() {
@@ -166,7 +191,6 @@
                 Log.w(TAG, "ACTION_CLOSE_SYSTEM_DIALOGS received");
                 mCurrentDialog.dismissWithoutCallback(true /* animate */);
                 mCurrentDialog = null;
-                mOrientationListener.disable();
 
                 for (Callback cb : mCallbacks) {
                     cb.onBiometricPromptDismissed();
@@ -200,7 +224,6 @@
                         Log.e(TAG, "Evicting client due to: " + topPackage);
                         mCurrentDialog.dismissWithoutCallback(true /* animate */);
                         mCurrentDialog = null;
-                        mOrientationListener.disable();
 
                         for (Callback cb : mCallbacks) {
                             cb.onBiometricPromptDismissed();
@@ -266,7 +289,6 @@
             mUdfpsController.setAuthControllerUpdateUdfpsLocation(this::updateUdfpsLocation);
             mUdfpsController.setHalControlsIllumination(mUdfpsProps.get(0).halControlsIllumination);
             mUdfpsBounds = mUdfpsProps.get(0).getLocation().getRect();
-            updateUdfpsLocation();
         }
 
         mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null;
@@ -281,7 +303,7 @@
                         TYPE_FINGERPRINT, userId, sensorId, hasEnrollments));
             }
         });
-        updateFingerprintLocation();
+        updateSensorLocations();
 
         for (Callback cb : mCallbacks) {
             cb.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
@@ -479,11 +501,11 @@
     /**
      * @return where the UDFPS exists on the screen in pixels in portrait mode.
      */
-    @Nullable public PointF getUdfpsLocation() {
+    @Nullable public Point getUdfpsLocation() {
         if (mUdfpsController == null || mUdfpsBounds == null) {
             return null;
         }
-        return new PointF(mUdfpsBounds.centerX(), mUdfpsBounds.centerY());
+        return new Point(mUdfpsBounds.centerX(), mUdfpsBounds.centerY());
     }
 
     /**
@@ -497,45 +519,105 @@
     }
 
     /**
-     * @return the scale factor representing the user's current resolution / the stable
-     * (default) resolution
+     * Gets the cached scale factor representing the user's current resolution / the stable
+     * (default) resolution.
      */
     public float getScaleFactor() {
-        if (mUdfpsController == null || mUdfpsController.mOverlayParams == null) {
-            return 1f;
-        }
-        return mUdfpsController.mOverlayParams.getScaleFactor();
+        return mScaleFactor;
     }
 
     /**
-     * @return where the fingerprint sensor exists in pixels in portrait mode. devices without an
-     * overridden value will use the default value even if they don't have a fingerprint sensor
+     * Updates the current display info and cached scale factor & sensor locations.
+     * Getting the display info is a relatively expensive call, so avoid superfluous calls.
      */
-    @Nullable public PointF getFingerprintSensorLocation() {
+    private void updateSensorLocations() {
+        mDisplay.getDisplayInfo(mCachedDisplayInfo);
+
+        final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio(
+                mStableDisplaySize.x, mStableDisplaySize.y, mCachedDisplayInfo.getNaturalWidth(),
+                mCachedDisplayInfo.getNaturalHeight());
+        if (scaleFactor == Float.POSITIVE_INFINITY) {
+            mScaleFactor = 1f;
+        } else {
+            mScaleFactor = scaleFactor;
+        }
+
+        updateUdfpsLocation();
+        updateFingerprintLocation();
+        updateFaceLocation();
+    }
+    /**
+     * @return where the fingerprint sensor exists in pixels in its natural orientation.
+     * Devices without location configs will use the default value even if they don't have a
+     * fingerprint sensor.
+     *
+     * May return null if the fingerprint sensor isn't available yet.
+     */
+    @Nullable private Point getFingerprintSensorLocationInNaturalOrientation() {
         if (getUdfpsLocation() != null) {
             return getUdfpsLocation();
         }
-        return mFingerprintLocation;
+        return new Point(
+                (int) (mFingerprintSensorLocationDefault.x * mScaleFactor),
+                (int) (mFingerprintSensorLocationDefault.y * mScaleFactor)
+        );
     }
 
     /**
-     * @return where the face authentication sensor exists relative to the screen in pixels in
-     * portrait mode.
+     * @return where the fingerprint sensor exists in pixels exists the current device orientation.
+     * Devices without location configs will use the default value even if they don't have a
+     * fingerprint sensor.
      */
-    @Nullable public PointF getFaceAuthSensorLocation() {
-        if (mFaceProps == null || mFaceAuthSensorLocation == null) {
-            return null;
+    @Nullable public Point getFingerprintSensorLocation() {
+        return mFingerprintSensorLocation;
+    }
+
+    private void updateFingerprintLocation() {
+        if (mFpProps == null) {
+            mFingerprintSensorLocation = null;
+        } else {
+            mFingerprintSensorLocation = rotateToCurrentOrientation(
+                    getFingerprintSensorLocationInNaturalOrientation(),
+                    mCachedDisplayInfo);
         }
-        DisplayInfo displayInfo = new DisplayInfo();
-        mContext.getDisplay().getDisplayInfo(displayInfo);
-        final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio(
-                mStableDisplaySize.x, mStableDisplaySize.y, displayInfo.getNaturalWidth(),
-                displayInfo.getNaturalHeight());
-        if (scaleFactor == Float.POSITIVE_INFINITY) {
-            return new PointF(mFaceAuthSensorLocation.x, mFaceAuthSensorLocation.y);
+    }
+
+    /**
+     * @return where the face sensor exists in pixels in the current device orientation. Returns
+     * null if no face sensor exists.
+     */
+    @Nullable public Point getFaceSensorLocation() {
+        return mFaceSensorLocation;
+    }
+
+    private void updateFaceLocation() {
+        if (mFaceProps == null || mFaceSensorLocationDefault == null) {
+            mFaceSensorLocation = null;
+        } else {
+            mFaceSensorLocation = rotateToCurrentOrientation(
+                    new Point(
+                            (int) (mFaceSensorLocationDefault.x * mScaleFactor),
+                            (int) (mFaceSensorLocationDefault.y * mScaleFactor)),
+                    mCachedDisplayInfo
+            );
         }
-        return new PointF(mFaceAuthSensorLocation.x * scaleFactor,
-                mFaceAuthSensorLocation.y * scaleFactor);
+    }
+
+    /**
+     * @param inOutPoint point on the display in pixels. Going in, represents the point
+     *                   in the device's natural orientation. Going out, represents
+     *                   the point in the display's current orientation.
+     * @param displayInfo currently display information to use to rotate the point
+     */
+    @VisibleForTesting
+    protected Point rotateToCurrentOrientation(Point inOutPoint, DisplayInfo displayInfo) {
+        RotationUtils.rotatePoint(
+                inOutPoint,
+                displayInfo.rotation,
+                displayInfo.getNaturalWidth(),
+                displayInfo.getNaturalHeight()
+        );
+        return inOutPoint;
     }
 
     /**
@@ -596,10 +678,10 @@
             @NonNull StatusBarStateController statusBarStateController,
             @NonNull InteractionJankMonitor jankMonitor,
             @Main Handler handler,
-            @Background DelayableExecutor bgExecutor) {
+            @Background DelayableExecutor bgExecutor,
+            @NonNull VibratorHelper vibrator) {
         super(context);
         mExecution = execution;
-        mWakefulnessLifecycle = wakefulnessLifecycle;
         mUserManager = userManager;
         mLockPatternUtils = lockPatternUtils;
         mHandler = handler;
@@ -614,6 +696,7 @@
         mWindowManager = windowManager;
         mInteractionJankMonitor = jankMonitor;
         mUdfpsEnrolledForUser = new SparseBooleanArray();
+        mVibratorHelper = vibrator;
 
         mOrientationListener = new BiometricDisplayListener(
                 context,
@@ -625,54 +708,58 @@
                     return Unit.INSTANCE;
                 });
 
+        mWakefulnessLifecycle = wakefulnessLifecycle;
+        mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
+            @Override
+            public void onFinishedWakingUp() {
+                notifyDozeChanged(mStatusBarStateController.isDozing(), WAKEFULNESS_AWAKE);
+            }
+
+            @Override
+            public void onStartedGoingToSleep() {
+                notifyDozeChanged(mStatusBarStateController.isDozing(), WAKEFULNESS_GOING_TO_SLEEP);
+            }
+        });
+
         mStatusBarStateController = statusBarStateController;
         mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() {
             @Override
             public void onDozingChanged(boolean isDozing) {
-                notifyDozeChanged(isDozing);
+                notifyDozeChanged(isDozing, wakefulnessLifecycle.getWakefulness());
             }
         });
 
         mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
-
         int[] faceAuthLocation = context.getResources().getIntArray(
                 com.android.systemui.R.array.config_face_auth_props);
         if (faceAuthLocation == null || faceAuthLocation.length < 2) {
-            mFaceAuthSensorLocation = null;
+            mFaceSensorLocationDefault = null;
         } else {
-            mFaceAuthSensorLocation = new PointF(
-                    (float) faceAuthLocation[0],
-                    (float) faceAuthLocation[1]);
+            mFaceSensorLocationDefault = new Point(
+                    faceAuthLocation[0],
+                    faceAuthLocation[1]);
         }
 
-        updateFingerprintLocation();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-
-        context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED);
-        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
-    }
-
-    private int getDisplayWidth() {
-        DisplayInfo displayInfo = new DisplayInfo();
-        mContext.getDisplay().getDisplayInfo(displayInfo);
-        return displayInfo.getNaturalWidth();
-    }
-
-    private void updateFingerprintLocation() {
-        int xLocation = getDisplayWidth() / 2;
+        mDisplay = mContext.getDisplay();
+        mDisplay.getDisplayInfo(mCachedDisplayInfo);
+        int xFpLocation = mCachedDisplayInfo.getNaturalWidth() / 2;
         try {
-            xLocation = mContext.getResources().getDimensionPixelSize(
+            xFpLocation = mContext.getResources().getDimensionPixelSize(
                     com.android.systemui.R.dimen
                             .physical_fingerprint_sensor_center_screen_location_x);
         } catch (Resources.NotFoundException e) {
         }
-        int yLocation = mContext.getResources().getDimensionPixelSize(
-                com.android.systemui.R.dimen.physical_fingerprint_sensor_center_screen_location_y);
-        mFingerprintLocation = new PointF(
-                xLocation,
-                yLocation);
+        mFingerprintSensorLocationDefault = new Point(
+                xFpLocation,
+                mContext.getResources().getDimensionPixelSize(com.android.systemui.R.dimen
+                        .physical_fingerprint_sensor_center_screen_location_y)
+        );
+        updateSensorLocations();
+
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED);
+        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
     }
 
     // TODO(b/229290039): UDFPS controller should manage its dimensions on its own. Remove this.
@@ -681,19 +768,14 @@
     // updateFingerprintLocation in such a case are unclear.
     private void updateUdfpsLocation() {
         if (mUdfpsController != null) {
-            final DisplayInfo displayInfo = new DisplayInfo();
-            mContext.getDisplay().getDisplayInfo(displayInfo);
-            final float scaleFactor = android.util.DisplayUtils.getPhysicalPixelDisplaySizeRatio(
-                    mStableDisplaySize.x, mStableDisplaySize.y, displayInfo.getNaturalWidth(),
-                    displayInfo.getNaturalHeight());
-
             final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0);
             final Rect previousUdfpsBounds = mUdfpsBounds;
             mUdfpsBounds = udfpsProp.getLocation().getRect();
-            mUdfpsBounds.scale(scaleFactor);
+            mUdfpsBounds.scale(mScaleFactor);
             mUdfpsController.updateOverlayParams(udfpsProp.sensorId,
-                    new UdfpsOverlayParams(mUdfpsBounds, displayInfo.getNaturalWidth(),
-                            displayInfo.getNaturalHeight(), scaleFactor, displayInfo.rotation));
+                    new UdfpsOverlayParams(mUdfpsBounds, mCachedDisplayInfo.getNaturalWidth(),
+                            mCachedDisplayInfo.getNaturalHeight(), mScaleFactor,
+                            mCachedDisplayInfo.rotation));
             if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) {
                 for (Callback cb : mCallbacks) {
                     cb.onUdfpsLocationChanged();
@@ -733,18 +815,23 @@
 
         mStableDisplaySize = mDisplayManager.getStableDisplaySize();
         mActivityTaskManager.registerTaskStackListener(mTaskStackListener);
+        mOrientationListener.enable();
+        updateSensorLocations();
     }
 
     @Override
     public void setBiometicContextListener(IBiometricContextListener listener) {
         mBiometricContextListener = listener;
-        notifyDozeChanged(mStatusBarStateController.isDozing());
+        notifyDozeChanged(mStatusBarStateController.isDozing(),
+                mWakefulnessLifecycle.getWakefulness());
     }
 
-    private void notifyDozeChanged(boolean isDozing) {
+    private void notifyDozeChanged(boolean isDozing,
+            @WakefulnessLifecycle.Wakefulness int wakefullness) {
         if (mBiometricContextListener != null) {
             try {
-                mBiometricContextListener.onDozeChanged(isDozing);
+                final boolean isAwake = wakefullness == WAKEFULNESS_AWAKE;
+                mBiometricContextListener.onDozeChanged(isDozing, isAwake);
             } catch (RemoteException e) {
                 Log.w(TAG, "failed to notify initial doze state");
             }
@@ -819,6 +906,8 @@
     public void onBiometricAuthenticated(@Modality int modality) {
         if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: ");
 
+        vibrateSuccess(modality);
+
         if (mCurrentDialog != null) {
             mCurrentDialog.onAuthenticationSucceeded(modality);
         } else {
@@ -866,6 +955,8 @@
             Log.d(TAG, String.format("onBiometricError(%d, %d, %d)", modality, error, vendorCode));
         }
 
+        vibrateError(modality);
+
         final boolean isLockout = (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT)
                 || (error == BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT);
 
@@ -933,7 +1024,6 @@
         // BiometricService will have already sent the callback to the client in this case.
         // This avoids a round trip to SystemUI. So, just dismiss the dialog and we're done.
         mCurrentDialog = null;
-        mOrientationListener.disable();
     }
 
     /**
@@ -1024,7 +1114,6 @@
         }
         mCurrentDialog = newDialog;
         mCurrentDialog.show(mWindowManager, savedState);
-        mOrientationListener.enable();
 
         if (!promptInfo.isAllowBackgroundAuthentication()) {
             mHandler.post(this::cancelIfOwnerIsNotInForeground);
@@ -1043,14 +1132,12 @@
 
         mReceiver = null;
         mCurrentDialog = null;
-        mOrientationListener.disable();
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        updateFingerprintLocation();
-        updateUdfpsLocation();
+        updateSensorLocations();
 
         // Save the state of the current dialog (buttons showing, etc)
         if (mCurrentDialog != null) {
@@ -1058,7 +1145,6 @@
             mCurrentDialog.onSaveState(savedState);
             mCurrentDialog.dismissWithoutCallback(false /* animate */);
             mCurrentDialog = null;
-            mOrientationListener.disable();
 
             // Only show the dialog if necessary. If it was animating out, the dialog is supposed
             // to send its pending callback immediately.
@@ -1079,8 +1165,7 @@
     }
 
     private void onOrientationChanged() {
-        updateFingerprintLocation();
-        updateUdfpsLocation();
+        updateSensorLocations();
         if (mCurrentDialog != null) {
             mCurrentDialog.onOrientationChanged();
         }
@@ -1090,6 +1175,7 @@
             PromptInfo promptInfo, boolean requireConfirmation, int userId, int[] sensorIds,
             String opPackageName, boolean skipIntro, long operationId, long requestId,
             @BiometricMultiSensorMode int multiSensorConfig,
+
             @NonNull WakefulnessLifecycle wakefulnessLifecycle,
             @NonNull UserManager userManager,
             @NonNull LockPatternUtils lockPatternUtils) {
@@ -1103,9 +1189,7 @@
                 .setOperationId(operationId)
                 .setRequestId(requestId)
                 .setMultiSensorConfig(multiSensorConfig)
-                .setScaleFactorProvider(() -> {
-                    return getScaleFactor();
-                })
+                .setScaleFactorProvider(() -> getScaleFactor())
                 .build(bgExecutor, sensorIds, mFpProps, mFaceProps, wakefulnessLifecycle,
                         userManager, lockPatternUtils, mInteractionJankMonitor);
     }
@@ -1114,8 +1198,14 @@
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         final AuthDialog dialog = mCurrentDialog;
         pw.println("  stableDisplaySize=" + mStableDisplaySize);
-        pw.println("  faceAuthSensorLocation=" + mFaceAuthSensorLocation);
-        pw.println("  fingerprintLocation=" + mFingerprintLocation);
+        pw.println("  mCachedDisplayInfo=" + mCachedDisplayInfo);
+        pw.println("  mScaleFactor=" + mScaleFactor);
+        pw.println("  faceAuthSensorLocationDefault=" + mFaceSensorLocationDefault);
+        pw.println("  faceAuthSensorLocation=" + getFaceSensorLocation());
+        pw.println("  fingerprintSensorLocationDefault=" + mFingerprintSensorLocationDefault);
+        pw.println("  fingerprintSensorLocationInNaturalOrientation="
+                + getFingerprintSensorLocationInNaturalOrientation());
+        pw.println("  fingerprintSensorLocation=" + getFingerprintSensorLocation());
         pw.println("  udfpsBounds=" + mUdfpsBounds);
         pw.println("  allFingerprintAuthenticatorsRegistered="
                 + mAllFingerprintAuthenticatorsRegistered);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index 51f39b3..cd0fc37 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -48,6 +48,8 @@
     String KEY_BIOMETRIC_SENSOR_TYPE = "sensor_type";
     String KEY_BIOMETRIC_SENSOR_PROPS = "sensor_props";
 
+    String KEY_BIOMETRIC_ORIENTATION_CHANGED = "orientation_changed";
+
     int SIZE_UNKNOWN = 0;
     /**
      * Minimal UI, showing only biometric icon.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index fd3f600..35d96c9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -20,7 +20,7 @@
 import android.animation.AnimatorListenerAdapter
 import android.animation.ValueAnimator
 import android.content.Context
-import android.graphics.PointF
+import android.graphics.Point
 import android.hardware.biometrics.BiometricFingerprintConstants
 import android.hardware.biometrics.BiometricSourceType
 import android.util.Log
@@ -79,8 +79,8 @@
     @VisibleForTesting
     internal var startLightRevealScrimOnKeyguardFadingAway = false
     var lightRevealScrimAnimator: ValueAnimator? = null
-    var fingerprintSensorLocation: PointF? = null
-    private var faceSensorLocation: PointF? = null
+    var fingerprintSensorLocation: Point? = null
+    private var faceSensorLocation: Point? = null
     private var circleReveal: LightRevealEffect? = null
 
     private var udfpsController: UdfpsController? = null
@@ -131,10 +131,10 @@
                 circleReveal = CircleReveal(
                         it.x,
                         it.y,
-                        0f,
+                        0,
                         Math.max(
-                                Math.max(it.x, centralSurfaces.displayWidth - it.x),
-                                Math.max(it.y, centralSurfaces.displayHeight - it.y)
+                                Math.max(it.x, centralSurfaces.displayWidth.toInt() - it.x),
+                                Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
                         )
                 )
                 showUnlockedRipple()
@@ -148,10 +148,10 @@
                 circleReveal = CircleReveal(
                         it.x,
                         it.y,
-                        0f,
+                        0,
                         Math.max(
-                                Math.max(it.x, centralSurfaces.displayWidth - it.x),
-                                Math.max(it.y, centralSurfaces.displayHeight - it.y)
+                                Math.max(it.x, centralSurfaces.displayWidth.toInt() - it.x),
+                                Math.max(it.y, centralSurfaces.displayHeight.toInt() - it.y)
                         )
                 )
                 showUnlockedRipple()
@@ -228,7 +228,7 @@
 
     fun updateSensorLocation() {
         fingerprintSensorLocation = authController.fingerprintSensorLocation
-        faceSensorLocation = authController.faceAuthSensorLocation
+        faceSensorLocation = authController.faceSensorLocation
     }
 
     private fun updateRippleColor() {
@@ -362,9 +362,8 @@
                             invalidCommand(pw)
                             return
                         }
-                        pw.println("custom ripple sensorLocation=" + args[1].toFloat() + ", " +
-                            args[2].toFloat())
-                        mView.setSensorLocation(PointF(args[1].toFloat(), args[2].toFloat()))
+                        pw.println("custom ripple sensorLocation=" + args[1] + ", " + args[2])
+                        mView.setSensorLocation(Point(args[1].toInt(), args[2].toInt()))
                         showUnlockedRipple()
                     }
                     else -> invalidCommand(pw)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 1c57480..c93fe6a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -23,7 +23,7 @@
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Paint
-import android.graphics.PointF
+import android.graphics.Point
 import android.util.AttributeSet
 import android.view.View
 import android.view.animation.PathInterpolator
@@ -68,7 +68,7 @@
             dwellShader.maxRadius = value
             field = value
         }
-    private var dwellOrigin: PointF = PointF()
+    private var dwellOrigin: Point = Point()
         set(value) {
             dwellShader.origin = value
             field = value
@@ -78,9 +78,9 @@
             rippleShader.setMaxSize(value * 2f, value * 2f)
             field = value
         }
-    private var origin: PointF = PointF()
+    private var origin: Point = Point()
         set(value) {
-            rippleShader.setCenter(value.x, value.y)
+            rippleShader.setCenter(value.x.toFloat(), value.y.toFloat())
             field = value
         }
 
@@ -97,12 +97,12 @@
         visibility = GONE
     }
 
-    fun setSensorLocation(location: PointF) {
+    fun setSensorLocation(location: Point) {
         origin = location
         radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat()
     }
 
-    fun setFingerprintSensorLocation(location: PointF, sensorRadius: Float) {
+    fun setFingerprintSensorLocation(location: Point, sensorRadius: Float) {
         origin = location
         radius = maxOf(location.x, location.y, width - location.x, height - location.y).toFloat()
         dwellOrigin = location
@@ -349,13 +349,15 @@
         if (drawDwell) {
             val maskRadius = (1 - (1 - dwellShader.progress) * (1 - dwellShader.progress) *
                     (1 - dwellShader.progress)) * dwellRadius * 2f
-            canvas?.drawCircle(dwellOrigin.x, dwellOrigin.y, maskRadius, dwellPaint)
+            canvas?.drawCircle(dwellOrigin.x.toFloat(), dwellOrigin.y.toFloat(),
+                    maskRadius, dwellPaint)
         }
 
         if (drawRipple) {
             val mask = (1 - (1 - rippleShader.progress) * (1 - rippleShader.progress) *
                     (1 - rippleShader.progress)) * radius * 2f
-            canvas?.drawCircle(origin.x, origin.y, mask, ripplePaint)
+            canvas?.drawCircle(origin.x.toFloat(), origin.y.toFloat(),
+                    mask, ripplePaint)
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
new file mode 100644
index 0000000..f2d8aaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
@@ -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.systemui.biometrics
+
+/**
+ * Provides whether an acquired error message should be shown immediately when its received (see
+ * [shouldDefer]) or should be shown when the biometric error is received [getDeferredMessage].
+ * @property excludedMessages messages that are excluded from counts
+ * @property messagesToDefer messages that shouldn't show immediately when received, but may be
+ * shown later if the message is the most frequent message processed and meets [THRESHOLD]
+ * percentage of all messages (excluding [excludedMessages])
+ */
+class BiometricMessageDeferral(
+    private val excludedMessages: Set<Int>,
+    private val messagesToDefer: Set<Int>
+) {
+    private val msgCounts: MutableMap<Int, Int> = HashMap() // msgId => frequency of msg
+    private val msgIdToCharSequence: MutableMap<Int, CharSequence> = HashMap() // msgId => message
+    private var totalRelevantMessages = 0
+    private var mostFrequentMsgIdToDefer: Int? = null
+
+    /** Reset all saved counts. */
+    fun reset() {
+        totalRelevantMessages = 0
+        msgCounts.clear()
+        msgIdToCharSequence.clear()
+    }
+
+    /** Whether the given message should be deferred instead of being shown immediately. */
+    fun shouldDefer(acquiredMsgId: Int): Boolean {
+        return messagesToDefer.contains(acquiredMsgId)
+    }
+
+    /**
+     * Adds the acquiredMsgId to the counts if it's not in [excludedMessages]. We still count
+     * messages that shouldn't be deferred in these counts.
+     */
+    fun processMessage(acquiredMsgId: Int, helpString: CharSequence) {
+        if (excludedMessages.contains(acquiredMsgId)) {
+            return
+        }
+
+        totalRelevantMessages++
+        msgIdToCharSequence[acquiredMsgId] = helpString
+
+        val newAcquiredMsgCount = msgCounts.getOrDefault(acquiredMsgId, 0) + 1
+        msgCounts[acquiredMsgId] = newAcquiredMsgCount
+        if (
+            messagesToDefer.contains(acquiredMsgId) &&
+                (mostFrequentMsgIdToDefer == null ||
+                    newAcquiredMsgCount > msgCounts.getOrDefault(mostFrequentMsgIdToDefer!!, 0))
+        ) {
+            mostFrequentMsgIdToDefer = acquiredMsgId
+        }
+    }
+
+    /**
+     * Get the most frequent deferred message that meets the [THRESHOLD] percentage of processed
+     * messages excluding [excludedMessages].
+     * @return null if no messages have been deferred OR deferred messages didn't meet the
+     * [THRESHOLD] percentage of messages to show.
+     */
+    fun getDeferredMessage(): CharSequence? {
+        mostFrequentMsgIdToDefer?.let {
+            if (msgCounts.getOrDefault(it, 0) > (THRESHOLD * totalRelevantMessages)) {
+                return msgIdToCharSequence[mostFrequentMsgIdToDefer]
+            }
+        }
+
+        return null
+    }
+    companion object {
+        const val THRESHOLD = .5f
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt b/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt
index 979fe33..e5c4fb4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/DwellRippleShader.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.biometrics
 
-import android.graphics.PointF
+import android.graphics.Point
 import android.graphics.RuntimeShader
 import android.util.MathUtils
 
@@ -94,10 +94,10 @@
     /**
      * Origin coordinate of the ripple.
      */
-    var origin: PointF = PointF()
+    var origin: Point = Point()
         set(value) {
             field = value
-            setFloatUniform("in_origin", value.x, value.y)
+            setFloatUniform("in_origin", value.x.toFloat(), value.y.toFloat())
         }
 
     /**
@@ -107,7 +107,7 @@
         set(value) {
             field = value
             setFloatUniform("in_radius",
-                    (1 - (1 - value) * (1 - value) * (1 - value))* maxRadius)
+                    (1 - (1 - value) * (1 - value) * (1 - value)) * maxRadius)
             setFloatUniform("in_blur", MathUtils.lerp(1f, 0.7f, value))
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d1589b2..7f2680b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -52,6 +52,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.LatencyTracker;
+import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.biometrics.dagger.BiometricsBackground;
@@ -852,7 +853,9 @@
             playStartHaptic();
 
             if (!mKeyguardUpdateMonitor.isFaceDetectionRunning()) {
-                mKeyguardUpdateMonitor.requestFaceAuth(/* userInitiatedRequest */ false);
+                mKeyguardUpdateMonitor.requestFaceAuth(
+                        /* userInitiatedRequest */ false,
+                        FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
             }
         }
         mOnFingerDown = true;
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/camera/CameraGestureHelper.kt b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
index 4fe2dd8..e2ef247 100644
--- a/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/camera/CameraGestureHelper.kt
@@ -33,7 +33,6 @@
 import com.android.systemui.ActivityIntentHelper
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.shade.NotificationPanelViewController
 import com.android.systemui.shared.system.ActivityManagerKt.isInForeground
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -117,7 +116,7 @@
                     )
                 } catch (e: RemoteException) {
                     Log.w(
-                        NotificationPanelViewController.TAG,
+                        "CameraGestureHelper",
                         "Unable to start camera activity",
                         e
                     )
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
index da675de..dec3d6b 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/charging/WiredChargingRippleController.kt
@@ -200,8 +200,7 @@
     }
 
     private fun updateRippleColor() {
-        rippleView.setColor(
-                Utils.getColorAttr(context, android.R.attr.colorAccent).defaultColor)
+        rippleView.setColor(Utils.getColorAttr(context, android.R.attr.colorAccent).defaultColor)
     }
 
     inner class ChargingRippleCommand : Command {
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
new file mode 100644
index 0000000..e82d0ea
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingAnimation.java
@@ -0,0 +1,254 @@
+/*
+ * 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.charging;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Gravity;
+import android.view.WindowManager;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.ripple.RippleShader.RippleShape;
+
+/**
+ * A WirelessChargingAnimation is a view containing view + animation for wireless charging.
+ * @hide
+ */
+public class WirelessChargingAnimation {
+    public static final int UNKNOWN_BATTERY_LEVEL = -1;
+    public static final long DURATION = 1500;
+    private static final String TAG = "WirelessChargingView";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private final WirelessChargingView mCurrentWirelessChargingView;
+    private static WirelessChargingView mPreviousWirelessChargingView;
+
+    public interface Callback {
+        void onAnimationStarting();
+        void onAnimationEnded();
+    }
+
+    /**
+     * Constructs an empty WirelessChargingAnimation object.  If looper is null,
+     * Looper.myLooper() is used.  Must set
+     * {@link WirelessChargingAnimation#mCurrentWirelessChargingView}
+     * before calling {@link #show} - can be done through {@link #makeWirelessChargingAnimation}.
+     * @hide
+     */
+    private WirelessChargingAnimation(@NonNull Context context, @Nullable Looper looper,
+            int transmittingBatteryLevel, int batteryLevel, Callback callback, boolean isDozing,
+            RippleShape rippleShape, UiEventLogger uiEventLogger) {
+        mCurrentWirelessChargingView = new WirelessChargingView(context, looper,
+                transmittingBatteryLevel, batteryLevel, callback, isDozing,
+                rippleShape, uiEventLogger);
+    }
+
+    /**
+     * Creates a wireless charging animation object populated with next view.
+     *
+     * @hide
+     */
+    public static WirelessChargingAnimation makeWirelessChargingAnimation(@NonNull Context context,
+            @Nullable Looper looper, int transmittingBatteryLevel, int batteryLevel,
+            Callback callback, boolean isDozing, RippleShape rippleShape,
+            UiEventLogger uiEventLogger) {
+        return new WirelessChargingAnimation(context, looper, transmittingBatteryLevel,
+                batteryLevel, callback, isDozing, rippleShape, uiEventLogger);
+    }
+
+    /**
+     * Creates a charging animation object using mostly default values for non-dozing and unknown
+     * battery level without charging number shown.
+     */
+    public static WirelessChargingAnimation makeChargingAnimationWithNoBatteryLevel(
+            @NonNull Context context, RippleShape rippleShape, UiEventLogger uiEventLogger) {
+        return makeWirelessChargingAnimation(context, null,
+                UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, null, false,
+                rippleShape, uiEventLogger);
+    }
+
+    /**
+     * Show the view for the specified duration.
+     */
+    public void show(long delay) {
+        if (mCurrentWirelessChargingView == null ||
+                mCurrentWirelessChargingView.mNextView == null) {
+            throw new RuntimeException("setView must have been called");
+        }
+
+        if (mPreviousWirelessChargingView != null) {
+            mPreviousWirelessChargingView.hide(0);
+        }
+
+        mPreviousWirelessChargingView = mCurrentWirelessChargingView;
+        mCurrentWirelessChargingView.show(delay);
+        mCurrentWirelessChargingView.hide(delay + DURATION);
+    }
+
+    private static class WirelessChargingView {
+        private static final int SHOW = 0;
+        private static final int HIDE = 1;
+
+        private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
+        private final Handler mHandler;
+        private final UiEventLogger mUiEventLogger;
+
+        private int mGravity;
+        private WirelessChargingLayout mView;
+        private WirelessChargingLayout mNextView;
+        private WindowManager mWM;
+        private Callback mCallback;
+
+        public WirelessChargingView(Context context, @Nullable Looper looper,
+                int transmittingBatteryLevel, int batteryLevel, Callback callback,
+                boolean isDozing, RippleShape rippleShape, UiEventLogger uiEventLogger) {
+            mCallback = callback;
+            mNextView = new WirelessChargingLayout(context, transmittingBatteryLevel, batteryLevel,
+                    isDozing, rippleShape);
+            mGravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER;
+            mUiEventLogger = uiEventLogger;
+
+            final WindowManager.LayoutParams params = mParams;
+            params.height = WindowManager.LayoutParams.MATCH_PARENT;
+            params.width = WindowManager.LayoutParams.MATCH_PARENT;
+            params.format = PixelFormat.TRANSLUCENT;
+            params.type = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+            params.setTitle("Charging Animation");
+            params.layoutInDisplayCutoutMode =
+                    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+            params.setFitInsetsTypes(0 /* ignore all system bar insets */);
+            params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+            params.setTrustedOverlay();
+
+            if (looper == null) {
+                // Use Looper.myLooper() if looper is not specified.
+                looper = Looper.myLooper();
+                if (looper == null) {
+                    throw new RuntimeException(
+                            "Can't display wireless animation on a thread that has not called "
+                                    + "Looper.prepare()");
+                }
+            }
+
+            mHandler = new Handler(looper, null) {
+                @Override
+                public void handleMessage(Message msg) {
+                    switch (msg.what) {
+                        case SHOW: {
+                            handleShow();
+                            break;
+                        }
+                        case HIDE: {
+                            handleHide();
+                            // Don't do this in handleHide() because it is also invoked by
+                            // handleShow()
+                            mNextView = null;
+                            break;
+                        }
+                    }
+                }
+            };
+        }
+
+        public void show(long delay) {
+            if (DEBUG) Slog.d(TAG, "SHOW: " + this);
+            mHandler.sendMessageDelayed(Message.obtain(mHandler, SHOW), delay);
+        }
+
+        public void hide(long duration) {
+            mHandler.removeMessages(HIDE);
+
+            if (DEBUG) Slog.d(TAG, "HIDE: " + this);
+            mHandler.sendMessageDelayed(Message.obtain(mHandler, HIDE), duration);
+        }
+
+        private void handleShow() {
+            if (DEBUG) {
+                Slog.d(TAG, "HANDLE SHOW: " + this + " mView=" + mView + " mNextView="
+                        + mNextView);
+            }
+
+            if (mView != mNextView) {
+                // remove the old view if necessary
+                handleHide();
+                mView = mNextView;
+                Context context = mView.getContext().getApplicationContext();
+                String packageName = mView.getContext().getOpPackageName();
+                if (context == null) {
+                    context = mView.getContext();
+                }
+                mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+                mParams.packageName = packageName;
+                mParams.hideTimeoutMilliseconds = DURATION;
+
+                if (mView.getParent() != null) {
+                    if (DEBUG) Slog.d(TAG, "REMOVE! " + mView + " in " + this);
+                    mWM.removeView(mView);
+                }
+                if (DEBUG) Slog.d(TAG, "ADD! " + mView + " in " + this);
+
+                try {
+                    if (mCallback != null) {
+                        mCallback.onAnimationStarting();
+                    }
+                    mWM.addView(mView, mParams);
+                    mUiEventLogger.log(WirelessChargingRippleEvent.WIRELESS_RIPPLE_PLAYED);
+                } catch (WindowManager.BadTokenException e) {
+                    Slog.d(TAG, "Unable to add wireless charging view. " + e);
+                }
+            }
+        }
+
+        private void handleHide() {
+            if (DEBUG) Slog.d(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
+            if (mView != null) {
+                if (mView.getParent() != null) {
+                    if (DEBUG) Slog.d(TAG, "REMOVE! " + mView + " in " + this);
+                    if (mCallback != null) {
+                        mCallback.onAnimationEnded();
+                    }
+                    mWM.removeViewImmediate(mView);
+                }
+
+                mView = null;
+            }
+        }
+
+        enum WirelessChargingRippleEvent implements UiEventLogger.UiEventEnum {
+            @UiEvent(doc = "Wireless charging ripple effect played")
+            WIRELESS_RIPPLE_PLAYED(830);
+
+            private final int mInt;
+            WirelessChargingRippleEvent(int id) {
+                mInt = id;
+            }
+
+            @Override public int getId() {
+                return mInt;
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
index 6da65d2..c0cc6b4 100644
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingLayout.java
@@ -16,9 +16,6 @@
 
 package com.android.systemui.charging;
 
-import static com.android.systemui.charging.WirelessChargingRippleControllerKt.DEFAULT_DURATION;
-import static com.android.systemui.charging.WirelessChargingRippleControllerKt.UNKNOWN_BATTERY_LEVEL;
-
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
@@ -33,54 +30,49 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import androidx.core.graphics.ColorUtils;
-
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.ripple.RippleShader.RippleShape;
 import com.android.systemui.ripple.RippleView;
+import com.android.systemui.ripple.RippleViewKt;
 
 import java.text.NumberFormat;
 
 /**
- * Layout that is used for wireless charging.
- *
- * <p>Wireless charging layout has {@link RippleView} and text view to show the battery level.
+ * @hide
  */
 final class WirelessChargingLayout extends FrameLayout {
+    private static final long CIRCLE_RIPPLE_ANIMATION_DURATION = 1500;
+    private static final long ROUNDED_BOX_RIPPLE_ANIMATION_DURATION = 1750;
     private static final int SCRIM_COLOR = 0x4C000000;
     private static final int SCRIM_FADE_DURATION = 300;
     private RippleView mRippleView;
 
     WirelessChargingLayout(Context context, int transmittingBatteryLevel, int batteryLevel,
-            boolean isDozing, RippleShape rippleShape, long duration) {
+            boolean isDozing, RippleShape rippleShape) {
         super(context);
-        init(context, null, transmittingBatteryLevel, batteryLevel, isDozing, rippleShape,
-                duration);
+        init(context, null, transmittingBatteryLevel, batteryLevel, isDozing, rippleShape);
     }
 
     private WirelessChargingLayout(Context context) {
         super(context);
-        init(context, null, /* isDozing= */ false, RippleShape.CIRCLE,
-                DEFAULT_DURATION);
+        init(context, null, /* isDozing= */ false, RippleShape.CIRCLE);
     }
 
     private WirelessChargingLayout(Context context, AttributeSet attrs) {
         super(context, attrs);
-        init(context, attrs, /* isDozing= */false, RippleShape.CIRCLE,
-                DEFAULT_DURATION);
+        init(context, attrs, /* isDozing= */false, RippleShape.CIRCLE);
     }
 
-    private void init(Context c, AttributeSet attrs, boolean isDozing, RippleShape rippleShape,
-            long duration) {
-        init(c, attrs, -1, -1, isDozing, rippleShape, duration);
+    private void init(Context c, AttributeSet attrs, boolean isDozing, RippleShape rippleShape) {
+        init(c, attrs, -1, -1, isDozing, rippleShape);
     }
 
     private void init(Context context, AttributeSet attrs, int transmittingBatteryLevel,
-            int batteryLevel, boolean isDozing, RippleShape rippleShape, long duration) {
+            int batteryLevel, boolean isDozing, RippleShape rippleShape) {
         final boolean showTransmittingBatteryLevel =
-                (transmittingBatteryLevel != UNKNOWN_BATTERY_LEVEL);
+                (transmittingBatteryLevel != WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL);
 
         // set style based on background
         int style = R.style.ChargingAnim_WallpaperBackground;
@@ -93,7 +85,7 @@
         // amount of battery:
         final TextView percentage = findViewById(R.id.wireless_charging_percentage);
 
-        if (batteryLevel != UNKNOWN_BATTERY_LEVEL) {
+        if (batteryLevel != WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL) {
             percentage.setText(NumberFormat.getPercentInstance().format(batteryLevel / 100f));
             percentage.setAlpha(0);
         }
@@ -132,6 +124,7 @@
         // play all animations together
         AnimatorSet animatorSet = new AnimatorSet();
         animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator);
+
         ValueAnimator scrimFadeInAnimator = ObjectAnimator.ofArgb(this,
                 "backgroundColor", Color.TRANSPARENT, SCRIM_COLOR);
         scrimFadeInAnimator.setDuration(SCRIM_FADE_DURATION);
@@ -140,21 +133,24 @@
                 "backgroundColor", SCRIM_COLOR, Color.TRANSPARENT);
         scrimFadeOutAnimator.setDuration(SCRIM_FADE_DURATION);
         scrimFadeOutAnimator.setInterpolator(Interpolators.LINEAR);
-        scrimFadeOutAnimator.setStartDelay(duration - SCRIM_FADE_DURATION);
+        scrimFadeOutAnimator.setStartDelay((rippleShape == RippleShape.CIRCLE
+                ? CIRCLE_RIPPLE_ANIMATION_DURATION : ROUNDED_BOX_RIPPLE_ANIMATION_DURATION)
+                - SCRIM_FADE_DURATION);
         AnimatorSet animatorSetScrim = new AnimatorSet();
         animatorSetScrim.playTogether(scrimFadeInAnimator, scrimFadeOutAnimator);
         animatorSetScrim.start();
 
         mRippleView = findViewById(R.id.wireless_charging_ripple);
         mRippleView.setupShader(rippleShape);
-        mRippleView.setDuration(duration);
         int color = Utils.getColorAttr(mRippleView.getContext(),
                 android.R.attr.colorAccent).getDefaultColor();
         if (mRippleView.getRippleShape() == RippleShape.ROUNDED_BOX) {
+            mRippleView.setDuration(ROUNDED_BOX_RIPPLE_ANIMATION_DURATION);
             mRippleView.setSparkleStrength(0.22f);
-            mRippleView.setColor(ColorUtils.setAlphaComponent(color, 28));
+            mRippleView.setColor(color, 28);
         } else {
-            mRippleView.setColor(ColorUtils.setAlphaComponent(color, 45));
+            mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION);
+            mRippleView.setColor(color, RippleViewKt.RIPPLE_DEFAULT_ALPHA);
         }
 
         OnAttachStateChangeListener listener = new OnAttachStateChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingRippleController.kt b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingRippleController.kt
deleted file mode 100644
index 8b5c7eb..0000000
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingRippleController.kt
+++ /dev/null
@@ -1,116 +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.charging
-
-import android.content.Context
-import android.view.WindowManager
-import androidx.annotation.VisibleForTesting
-import com.android.internal.logging.UiEventLogger
-import com.android.systemui.charging.WirelessChargingView.WirelessChargingRippleEvent
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.dagger.ChargingLog
-import com.android.systemui.util.concurrency.DelayableExecutor
-import javax.inject.Inject
-
-const val UNKNOWN_BATTERY_LEVEL = -1
-const val DEFAULT_DURATION: Long = 1500
-
-/**
- * Controls the wireless charging animation.
- */
-@SysUISingleton
-class WirelessChargingRippleController @Inject constructor(
-        context: Context,
-        private val uiEventLogger: UiEventLogger,
-        @Main private val delayableExecutor: DelayableExecutor,
-        @ChargingLog private val logBuffer: LogBuffer
-) {
-    private val windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE)
-            as WindowManager
-
-    @VisibleForTesting
-    var wirelessChargingView: WirelessChargingView? = null
-    private var callback: Callback? = null
-
-    companion object {
-        private const val TAG = "WirelessChargingRippleController"
-    }
-
-    /**
-     * Shows the wireless charging view with the given delay.
-     *
-     * If there's already the animation is playing, the new request will be disregarded.
-     * @param wirelessChargingView WirelessChargingView to display.
-     * @param delay the start delay of the WirelessChargingView.
-     * @param callback optional callback that is triggered on animations start and end.
-     */
-    fun show(wirelessChargingView: WirelessChargingView, delay: Long, callback: Callback? = null) {
-        // Avoid multiple animation getting triggered.
-        if (this.wirelessChargingView != null) {
-            logBuffer.log(TAG, LogLevel.INFO, "Already playing animation, disregard " +
-                    "$wirelessChargingView")
-            return
-        }
-
-        this.wirelessChargingView = wirelessChargingView
-        this.callback = callback
-
-        logBuffer.log(TAG, LogLevel.DEBUG, "SHOW: $wirelessChargingView")
-        delayableExecutor.executeDelayed({ showInternal() }, delay)
-
-        logBuffer.log(TAG, LogLevel.DEBUG, "HIDE: $wirelessChargingView")
-        delayableExecutor.executeDelayed({ hideInternal() }, delay + wirelessChargingView.duration)
-    }
-
-    private fun showInternal() {
-        if (wirelessChargingView == null) {
-            return
-        }
-
-        val chargingLayout = wirelessChargingView!!.getWirelessChargingLayout()
-        try {
-            callback?.onAnimationStarting()
-            windowManager.addView(chargingLayout, wirelessChargingView!!.wmLayoutParams)
-            uiEventLogger.log(WirelessChargingRippleEvent.WIRELESS_RIPPLE_PLAYED)
-        } catch (e: WindowManager.BadTokenException) {
-            logBuffer.log(TAG, LogLevel.ERROR, "Unable to add wireless charging view. $e")
-        }
-    }
-
-    private fun hideInternal() {
-        wirelessChargingView?.getWirelessChargingLayout().let {
-            callback?.onAnimationEnded()
-            if (it?.parent != null) {
-                windowManager.removeViewImmediate(it)
-            }
-        }
-        wirelessChargingView = null
-        callback = null
-    }
-
-    /**
-     * Callbacks that are triggered on animation events.
-     */
-    interface Callback {
-        /** Triggered when the animation starts playing. */
-        fun onAnimationStarting()
-        /** Triggered when the animation ends playing. */
-        fun onAnimationEnded()
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.kt b/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.kt
deleted file mode 100644
index d510cf6..0000000
--- a/packages/SystemUI/src/com/android/systemui/charging/WirelessChargingView.kt
+++ /dev/null
@@ -1,91 +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.charging
-
-import android.content.Context
-import android.graphics.PixelFormat
-import android.view.View
-import android.view.WindowManager
-import com.android.internal.logging.UiEvent
-import com.android.internal.logging.UiEventLogger.UiEventEnum
-import com.android.systemui.ripple.RippleShader.RippleShape
-
-/**
- * WirelessChargingView that encapsulates the current and next [WirelessChargingLayout]s.
- */
-class WirelessChargingView (
-        context: Context,
-        transmittingBatteryLevel: Int,
-        batteryLevel: Int,
-        isDozing: Boolean,
-        rippleShape: RippleShape,
-        val duration: Long,
-) {
-    companion object {
-        @JvmStatic
-        fun create(
-                context: Context,
-                transmittingBatteryLevel: Int,
-                batteryLevel: Int,
-                isDozing: Boolean,
-                rippleShape: RippleShape,
-                duration: Long = DEFAULT_DURATION
-        ): WirelessChargingView {
-            return WirelessChargingView(context, transmittingBatteryLevel, batteryLevel, isDozing,
-                    rippleShape, duration)
-        }
-
-        @JvmStatic
-        fun createWithNoBatteryLevel(
-                context: Context,
-                rippleShape: RippleShape,
-                duration: Long = DEFAULT_DURATION
-        ): WirelessChargingView {
-            return create(context,
-                    UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, false, rippleShape,
-                    duration)
-        }
-    }
-
-    val wmLayoutParams = WindowManager.LayoutParams().apply {
-        height = WindowManager.LayoutParams.MATCH_PARENT
-        width = WindowManager.LayoutParams.MATCH_PARENT
-        format = PixelFormat.TRANSLUCENT
-        type = WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
-        title = "Charging Animation"
-        layoutInDisplayCutoutMode =
-                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
-        fitInsetsTypes = 0
-        flags = (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE)
-        packageName = context.applicationContext.opPackageName
-        setTrustedOverlay()
-    }
-
-    private val wirelessChargingLayout: WirelessChargingLayout =
-            WirelessChargingLayout(context, transmittingBatteryLevel, batteryLevel, isDozing,
-                    rippleShape, duration)
-    fun getWirelessChargingLayout(): View = wirelessChargingLayout
-
-    internal enum class WirelessChargingRippleEvent(private val mInt: Int) : UiEventEnum {
-        @UiEvent(doc = "Wireless charging ripple effect played")
-        WIRELESS_RIPPLE_PLAYED(830);
-
-        override fun getId(): Int {
-            return mInt
-        }
-    }
-}
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/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
similarity index 62%
rename from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
rename to packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
index e62a63a..5d0e08f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Text.kt
@@ -12,20 +12,23 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
-package com.android.wm.shell.desktopmode;
+package com.android.systemui.common.shared.model
 
-import android.os.SystemProperties;
+import android.annotation.StringRes
 
 /**
- * Constants for desktop mode feature
+ * Models a text, that can either be already [loaded][Text.Loaded] or be a [reference]
+ * [Text.Resource] to a resource.
  */
-public class DesktopModeConstants {
+sealed class Text {
+    data class Loaded(
+        val text: String?,
+    ) : Text()
 
-    /**
-     * Flag to indicate whether desktop mode is available on the device
-     */
-    public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+    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/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
similarity index 60%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
index e62a63a..396e8bb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/TextViewBinder.kt
@@ -12,20 +12,20 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
-package com.android.wm.shell.desktopmode;
+package com.android.systemui.common.ui.binder
 
-import android.os.SystemProperties;
+import android.widget.TextView
+import com.android.systemui.common.shared.model.Text
 
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
-
-    /**
-     * Flag to indicate whether desktop mode is available on the device
-     */
-    public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+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/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/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
index 8ba6f1c..d60a222 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
@@ -26,6 +26,7 @@
 import com.android.systemui.screenshot.ActionProxyReceiver;
 import com.android.systemui.screenshot.DeleteScreenshotReceiver;
 import com.android.systemui.screenshot.SmartActionsReceiver;
+import com.android.systemui.volume.VolumePanelDialogReceiver;
 
 import dagger.Binds;
 import dagger.Module;
@@ -78,6 +79,15 @@
      */
     @Binds
     @IntoMap
+    @ClassKey(VolumePanelDialogReceiver.class)
+    public abstract BroadcastReceiver bindVolumePanelDialogReceiver(
+            VolumePanelDialogReceiver broadcastReceiver);
+
+    /**
+     *
+     */
+    @Binds
+    @IntoMap
     @ClassKey(PeopleSpaceWidgetPinnedReceiver.class)
     public abstract BroadcastReceiver bindPeopleSpaceWidgetPinnedReceiver(
             PeopleSpaceWidgetPinnedReceiver broadcastReceiver);
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/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 4157728..fbfc94a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -54,13 +54,11 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.dagger.StartCentralSurfacesModule;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.phone.DozeServiceHost;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -170,10 +168,6 @@
     abstract DockManager bindDockManager(DockManagerImpl dockManager);
 
     @Binds
-    abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
-            KeyguardEnvironmentImpl keyguardEnvironment);
-
-    @Binds
     abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
 
     @SysUISingleton
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/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 6db3e82..8bb27a7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.dagger
 
 import com.android.keyguard.KeyguardBiometricLockoutLogger
+import com.android.systemui.ChooserSelector
 import com.android.systemui.CoreStartable
 import com.android.systemui.LatencyTester
 import com.android.systemui.ScreenDecorations
@@ -60,6 +61,12 @@
     @ClassKey(AuthController::class)
     abstract fun bindAuthController(service: AuthController): CoreStartable
 
+    /** Inject into ChooserCoreStartable. */
+    @Binds
+    @IntoMap
+    @ClassKey(ChooserSelector::class)
+    abstract fun bindChooserSelector(sysui: ChooserSelector): CoreStartable
+
     /** Inject into ClipboardListener.  */
     @Binds
     @IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 1b060e2..318529b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -42,7 +42,6 @@
 import com.android.systemui.flags.FlagsModule;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.log.dagger.LogModule;
-import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.media.dagger.MediaProjectionModule;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarComponent;
@@ -65,7 +64,6 @@
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
@@ -95,7 +93,6 @@
 import com.android.systemui.wallet.dagger.WalletModule;
 import com.android.systemui.wmshell.BubblesManager;
 import com.android.wm.shell.bubbles.Bubbles;
-import com.android.wm.shell.dagger.DynamicOverride;
 
 import java.util.Optional;
 import java.util.concurrent.Executor;
@@ -225,11 +222,9 @@
             NotificationInterruptStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
-            NotificationGroupManagerLegacy groupManager,
             CommonNotifCollection notifCollection,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
-            DumpManager dumpManager,
             @Main Executor sysuiMainExecutor) {
         return Optional.ofNullable(BubblesManager.create(context,
                 bubblesOptional,
@@ -243,28 +238,12 @@
                 interruptionStateProvider,
                 zenModeController,
                 notifUserManager,
-                groupManager,
                 notifCollection,
                 notifPipeline,
                 sysUiState,
                 sysuiMainExecutor));
     }
 
-    @BindsOptionalOf
-    @DynamicOverride
-    abstract LowLightClockController optionalLowLightClockController();
-
-    @SysUISingleton
-    @Provides
-    static Optional<LowLightClockController> provideLowLightClockController(
-            @DynamicOverride Optional<LowLightClockController> optionalController) {
-        if (optionalController.isPresent() && optionalController.get().isLowLightClockEnabled()) {
-            return optionalController;
-        } else {
-            return Optional.empty();
-        }
-    }
-
     @Binds
     abstract FgsManagerController bindFgsManagerController(FgsManagerControllerImpl impl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt
new file mode 100644
index 0000000..cbed21c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderFactory.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.decor
+
+import android.content.res.Resources
+import android.util.Log
+import android.view.Display
+import android.view.DisplayCutout
+import android.view.DisplayInfo
+
+class CutoutDecorProviderFactory constructor(
+    private val res: Resources,
+    private val display: Display?,
+) : DecorProviderFactory() {
+
+    val displayInfo = DisplayInfo()
+
+    override val hasProviders: Boolean
+        get() {
+            display?.getDisplayInfo(displayInfo) ?: run {
+                Log.w(TAG, "display is null, can't update displayInfo")
+            }
+            return DisplayCutout.getFillBuiltInDisplayCutout(res, displayInfo.uniqueId)
+        }
+
+    override val providers: List<DecorProvider>
+        get() {
+            if (!hasProviders) {
+                return emptyList()
+            }
+
+            return ArrayList<DecorProvider>().also { list ->
+                // We need to update displayInfo before using it, but it has already updated during
+                // accessing hasProviders field
+                displayInfo.displayCutout?.getBoundBaseOnCurrentRotation()?.let { bounds ->
+                    for (bound in bounds) {
+                        list.add(
+                            CutoutDecorProviderImpl(bound.baseOnRotation0(displayInfo.rotation))
+                        )
+                    }
+                }
+            }
+        }
+}
+
+private const val TAG = "CutoutDecorProviderFactory"
diff --git a/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt
new file mode 100644
index 0000000..991b54e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/decor/CutoutDecorProviderImpl.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.decor
+
+import android.content.Context
+import android.view.DisplayCutout
+import android.view.Surface
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.R
+import com.android.systemui.ScreenDecorations.DisplayCutoutView
+
+class CutoutDecorProviderImpl(
+    @DisplayCutout.BoundsPosition override val alignedBound: Int
+) : BoundDecorProvider() {
+
+    override val viewId: Int = when (alignedBound) {
+        DisplayCutout.BOUNDS_POSITION_TOP -> R.id.display_cutout
+        DisplayCutout.BOUNDS_POSITION_LEFT -> R.id.display_cutout_left
+        DisplayCutout.BOUNDS_POSITION_RIGHT -> R.id.display_cutout_right
+        else -> R.id.display_cutout_bottom
+    }
+
+    override fun inflateView(
+        context: Context,
+        parent: ViewGroup,
+        @Surface.Rotation rotation: Int,
+        tintColor: Int
+    ): View {
+        return DisplayCutoutView(context, alignedBound).also { view ->
+            view.id = viewId
+            view.setColor(tintColor)
+            parent.addView(view)
+            view.updateRotation(rotation)
+        }
+    }
+
+    override fun onReloadResAndMeasure(
+        view: View,
+        reloadToken: Int,
+        @Surface.Rotation rotation: Int,
+        tintColor: Int,
+        displayUniqueId: String?
+    ) {
+        (view as? DisplayCutoutView)?.let { cutoutView ->
+            cutoutView.setColor(tintColor)
+            cutoutView.updateRotation(rotation)
+            cutoutView.onDisplayChanged(displayUniqueId)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
index de6d727..0681f50 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/DecorProvider.kt
@@ -32,7 +32,7 @@
     abstract val viewId: Int
 
     /** The number of total aligned bounds */
-    val numOfAlignedEdge: Int
+    val numOfAlignedBound: Int
         get() = alignedBounds.size
 
     /** The aligned bounds for the view which is created through inflateView() */
@@ -57,16 +57,8 @@
         @Surface.Rotation rotation: Int,
         tintColor: Int
     ): View
-}
 
-/**
- * Split list to 2 list, and return it back as Pair<>. The providers on the first list contains this
- * alignedBound element. The providers on the second list do not contain this alignedBound element
- */
-fun List<DecorProvider>.partitionAlignedBound(
-    @DisplayCutout.BoundsPosition alignedBound: Int
-): Pair<List<DecorProvider>, List<DecorProvider>> {
-    return partition { it.alignedBounds.contains(alignedBound) }
+    override fun toString() = "${javaClass.simpleName}{alignedBounds=$alignedBounds}"
 }
 
 /**
@@ -94,3 +86,61 @@
         listOf(alignedBound)
     }
 }
+
+/**
+ * Split list to 2 sub-lists, and return it back as Pair<>. The providers on the first list contains
+ * this alignedBound element. The providers on the second list do not contain this alignedBound
+ * element.
+ */
+fun List<DecorProvider>.partitionAlignedBound(
+    @DisplayCutout.BoundsPosition alignedBound: Int
+): Pair<List<DecorProvider>, List<DecorProvider>> {
+    return partition { it.alignedBounds.contains(alignedBound) }
+}
+
+/**
+ * Get the proper bound from DecorProvider list
+ * Time complexity: O(N), N is the number of providers
+ *
+ * Choose order
+ * 1. Return null if list is empty
+ * 2. If list contains BoundDecorProvider, return its alignedBound[0] because it is a must-have
+ *    bound
+ * 3. Return the bound with most DecorProviders
+ */
+fun List<DecorProvider>.getProperBound(): Int? {
+    // Return null if list is empty
+    if (isEmpty()) {
+        return null
+    }
+
+    // Choose alignedBounds[0] of BoundDecorProvider if any
+    val singleBoundProvider = firstOrNull { it.numOfAlignedBound == 1 }
+    if (singleBoundProvider != null) {
+        return singleBoundProvider.alignedBounds[0]
+    }
+
+    // Return the bound with most DecorProviders
+    val boundCount = intArrayOf(0, 0, 0, 0)
+    for (provider in this) {
+        for (bound in provider.alignedBounds) {
+            boundCount[bound]++
+        }
+    }
+    var maxCount = 0
+    var maxCountBound: Int? = null
+    val bounds = arrayOf(
+        // Put top and bottom at first to get the highest priority to be chosen
+        DisplayCutout.BOUNDS_POSITION_TOP,
+        DisplayCutout.BOUNDS_POSITION_BOTTOM,
+        DisplayCutout.BOUNDS_POSITION_LEFT,
+        DisplayCutout.BOUNDS_POSITION_RIGHT
+    )
+    for (bound in bounds) {
+        if (boundCount[bound] > maxCount) {
+            maxCountBound = bound
+            maxCount = boundCount[bound]
+        }
+    }
+    return maxCountBound
+}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
index 5925c57..ec0013b 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/FaceScanningProviderFactory.kt
@@ -32,8 +32,8 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.systemui.FaceScanningOverlay
 import com.android.systemui.biometrics.AuthController
-import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -55,7 +55,7 @@
     override val hasProviders: Boolean
         get() {
             if (!featureFlags.isEnabled(Flags.FACE_SCANNING_ANIM) ||
-                    authController.faceAuthSensorLocation == null) {
+                    authController.faceSensorLocation == null) {
                 return false
             }
 
@@ -159,7 +159,7 @@
         layoutParams.let { lp ->
             lp.width = ViewGroup.LayoutParams.MATCH_PARENT
             lp.height = ViewGroup.LayoutParams.MATCH_PARENT
-            authController.faceAuthSensorLocation?.y?.let { faceAuthSensorHeight ->
+            authController.faceSensorLocation?.y?.let { faceAuthSensorHeight ->
                 val faceScanningHeight = (faceAuthSensorHeight * 2).toInt()
                 when (rotation) {
                     Surface.ROTATION_0, Surface.ROTATION_180 ->
diff --git a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
index dfb0b5aa..45b8a08 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/OverlayWindow.kt
@@ -114,7 +114,8 @@
         pw.println("    rootView=$rootView")
         for (i in 0 until rootView.childCount) {
             val child = rootView.getChildAt(i)
-            pw.println("    child[$i]=$child")
+            val provider = viewProviderMap[child.id]?.second
+            pw.println("    child[$i]=$child $provider")
         }
     }
 }
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/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 32bc9de..ae41215 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -269,9 +269,10 @@
         return mPulseReason;
     }
 
-    /** Requests the PowerManager to wake up now. */
-    public void wakeUp() {
-        mDozeService.requestWakeUp();
+    /** Requests the PowerManager to wake up now.
+     * @param reason {@link DozeLog.Reason} that woke up the device.*/
+    public void wakeUp(@DozeLog.Reason int reason) {
+        mDozeService.requestWakeUp(reason);
     }
 
     public boolean isExecutingTransition() {
@@ -469,7 +470,7 @@
         void setDozeScreenState(int state);
 
         /** Request waking up. */
-        void requestWakeUp();
+        void requestWakeUp(@DozeLog.Reason int reason);
 
         /** Set screen brightness */
         void setDozeScreenBrightness(int brightness);
@@ -492,8 +493,8 @@
             }
 
             @Override
-            public void requestWakeUp() {
-                mDelegate.requestWakeUp();
+            public void requestWakeUp(@DozeLog.Reason int reason) {
+                mDelegate.requestWakeUp(reason);
             }
 
             @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index b06bf89..a2eb4e3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -113,10 +113,10 @@
     }
 
     @Override
-    public void requestWakeUp() {
+    public void requestWakeUp(@DozeLog.Reason int reason) {
         PowerManager pm = getSystemService(PowerManager.class);
         pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
-                "com.android.systemui:NODOZE");
+                "com.android.systemui:NODOZE " + DozeLog.reasonToString(reason));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 0014d6b..00ac8bc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.doze;
 
+import static android.app.StatusBarManager.SESSION_KEYGUARD;
+
 import static com.android.systemui.doze.DozeMachine.State.DOZE_SUSPEND_TRIGGERS;
 import static com.android.systemui.doze.DozeMachine.State.FINISH;
 import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
@@ -34,19 +36,19 @@
 import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeMachine.State;
 import com.android.systemui.doze.dagger.DozeScope;
+import com.android.systemui.log.SessionTracker;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.Assert;
-import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.sensors.AsyncSensorManager;
 import com.android.systemui.util.sensors.ProximityCheck;
 import com.android.systemui.util.sensors.ProximitySensor;
@@ -80,6 +82,7 @@
     private static final int PROXIMITY_TIMEOUT_DELAY_MS = 500;
 
     private final Context mContext;
+    private final SessionTracker mSessionTracker;
     private DozeMachine mMachine;
     private final DozeLog mDozeLog;
     private final DozeSensors mDozeSensors;
@@ -95,10 +98,8 @@
     private final ProximityCheck mProxCheck;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final AuthController mAuthController;
-    private final DelayableExecutor mMainExecutor;
     private final KeyguardStateController mKeyguardStateController;
     private final UiEventLogger mUiEventLogger;
-    private final DevicePostureController mDevicePostureController;
 
     private long mNotificationPulseTime;
     private boolean mPulsePending;
@@ -185,8 +186,8 @@
             ProximityCheck proxCheck,
             DozeLog dozeLog, BroadcastDispatcher broadcastDispatcher,
             SecureSettings secureSettings, AuthController authController,
-            @Main DelayableExecutor mainExecutor,
             UiEventLogger uiEventLogger,
+            SessionTracker sessionTracker,
             KeyguardStateController keyguardStateController,
             DevicePostureController devicePostureController) {
         mContext = context;
@@ -196,8 +197,8 @@
         mSensorManager = sensorManager;
         mWakeLock = wakeLock;
         mAllowPulseTriggers = true;
+        mSessionTracker = sessionTracker;
 
-        mDevicePostureController = devicePostureController;
         mDozeSensors = new DozeSensors(context, mSensorManager, dozeParameters,
                 config, wakeLock, this::onSensor, this::onProximityFar, dozeLog, proximitySensor,
                 secureSettings, authController, devicePostureController);
@@ -206,14 +207,9 @@
         mDozeLog = dozeLog;
         mBroadcastDispatcher = broadcastDispatcher;
         mAuthController = authController;
-        mMainExecutor = mainExecutor;
         mUiEventLogger = uiEventLogger;
         mKeyguardStateController = keyguardStateController;
     }
-    private final DevicePostureController.Callback mDevicePostureCallback =
-            posture -> {
-
-            };
 
     @Override
     public void setDozeMachine(DozeMachine dozeMachine) {
@@ -271,7 +267,7 @@
             mProxCheck.check(PROXIMITY_TIMEOUT_DELAY_MS, near -> {
                 final long end = SystemClock.uptimeMillis();
                 mDozeLog.traceProximityResult(
-                        near == null ? false : near,
+                        near != null && near,
                         end - start,
                         reason);
                 callback.accept(near);
@@ -354,17 +350,17 @@
         return mKeyguardStateController.isOccluded();
     }
 
-    private void gentleWakeUp(int reason) {
+    private void gentleWakeUp(@DozeLog.Reason int reason) {
         // Log screen wake up reason (lift/pickup, tap, double-tap)
         Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
-                .ifPresent(mUiEventLogger::log);
+                .ifPresent(uiEventEnum -> mUiEventLogger.log(uiEventEnum, getKeyguardSessionId()));
         if (mDozeParameters.getDisplayNeedsBlanking()) {
             // Let's prepare the display to wake-up by drawing black.
             // This will cover the hardware wake-up sequence, where the display
             // becomes black for a few frames.
             mDozeHost.setAodDimmingScrim(1f);
         }
-        mMachine.wakeUp();
+        mMachine.wakeUp(reason);
     }
 
     private void onProximityFar(boolean far) {
@@ -384,11 +380,10 @@
 
         if (state == DozeMachine.State.DOZE_PULSING
                 || state == DozeMachine.State.DOZE_PULSING_BRIGHT) {
-            boolean ignoreTouch = near;
             if (DEBUG) {
-                Log.i(TAG, "Prox changed, ignore touch = " + ignoreTouch);
+                Log.i(TAG, "Prox changed, ignore touch = " + near);
             }
-            mDozeHost.onIgnoreTouchWhilePulsing(ignoreTouch);
+            mDozeHost.onIgnoreTouchWhilePulsing(near);
         }
 
         if (far && (paused || pausing)) {
@@ -424,7 +419,8 @@
                     mMachine.requestState(DozeMachine.State.DOZE_AOD);
                     // Log sensor triggered
                     Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
-                            .ifPresent(mUiEventLogger::log);
+                            .ifPresent(uiEventEnum ->
+                                    mUiEventLogger.log(uiEventEnum, getKeyguardSessionId()));
                 }
             }, false /* alreadyPerformedProxCheck */, reason);
         } else {
@@ -564,7 +560,7 @@
 
         // Logs request pulse reason on AOD screen.
         Optional.ofNullable(DozingUpdateUiEvent.fromReason(reason))
-                .ifPresent(mUiEventLogger::log);
+                .ifPresent(uiEventEnum -> mUiEventLogger.log(uiEventEnum, getKeyguardSessionId()));
     }
 
     private boolean canPulse() {
@@ -583,6 +579,11 @@
         mMachine.requestPulse(reason);
     }
 
+    @Nullable
+    private InstanceId getKeyguardSessionId() {
+        return mSessionTracker.getSessionId(SESSION_KEYGUARD);
+    }
+
     @Override
     public void dump(PrintWriter pw) {
         pw.println(" mAodInterruptRunnable=" + mAodInterruptRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java
index d5db63d..75a97de 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java
@@ -35,7 +35,7 @@
 public class ComplicationUtils {
     /**
      * Converts a {@link com.android.settingslib.dream.DreamBackend.ComplicationType} to
-     * {@link ComplicationType}.
+     * {@link Complication.ComplicationType}.
      */
     @Complication.ComplicationType
     public static int convertComplicationType(@DreamBackend.ComplicationType int type) {
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
index 1c72e49..2503d3c 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
@@ -151,8 +151,8 @@
      * Controls behavior of the dream complication.
      */
     static class DreamHomeControlsChipViewController extends ViewController<ImageView> {
-        private static final boolean DEBUG = false;
         private static final String TAG = "DreamHomeControlsCtrl";
+        private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
         private final ActivityStarter mActivityStarter;
         private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java
new file mode 100644
index 0000000..21a51d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java
@@ -0,0 +1,135 @@
+/*
+ * 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.dreams.complication;
+
+import static com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent.DreamMediaEntryModule.DREAM_MEDIA_ENTRY_VIEW;
+import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_ENTRY_LAYOUT_PARAMS;
+
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent;
+import com.android.systemui.media.dream.MediaDreamComplication;
+import com.android.systemui.util.ViewController;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * A dream complication that shows a media entry chip to launch media control view.
+ */
+public class DreamMediaEntryComplication implements Complication {
+    private final DreamMediaEntryComplicationComponent.Factory mComponentFactory;
+
+    @Inject
+    public DreamMediaEntryComplication(
+            DreamMediaEntryComplicationComponent.Factory componentFactory) {
+        mComponentFactory = componentFactory;
+    }
+
+    @Override
+    public ViewHolder createView(ComplicationViewModel model) {
+        return mComponentFactory.create().getViewHolder();
+    }
+
+    /**
+     * Contains values/logic associated with the dream complication view.
+     */
+    public static class DreamMediaEntryViewHolder implements ViewHolder {
+        private final View mView;
+        private final ComplicationLayoutParams mLayoutParams;
+        private final DreamMediaEntryViewController mViewController;
+
+        @Inject
+        DreamMediaEntryViewHolder(
+                DreamMediaEntryViewController dreamMediaEntryViewController,
+                @Named(DREAM_MEDIA_ENTRY_VIEW) View view,
+                @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams
+        ) {
+            mView = view;
+            mLayoutParams = layoutParams;
+            mViewController = dreamMediaEntryViewController;
+            mViewController.init();
+        }
+
+        @Override
+        public View getView() {
+            return mView;
+        }
+
+        @Override
+        public ComplicationLayoutParams getLayoutParams() {
+            return mLayoutParams;
+        }
+    }
+
+    /**
+     * Controls behavior of the dream complication.
+     */
+    static class DreamMediaEntryViewController extends ViewController<View> {
+        private static final String TAG = "DreamMediaEntryVwCtrl";
+        private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+        private final DreamOverlayStateController mDreamOverlayStateController;
+        private final MediaDreamComplication mMediaComplication;
+
+        private boolean mMediaComplicationAdded;
+
+        @Inject
+        DreamMediaEntryViewController(
+                @Named(DREAM_MEDIA_ENTRY_VIEW) View view,
+                DreamOverlayStateController dreamOverlayStateController,
+                MediaDreamComplication mediaComplication) {
+            super(view);
+            mDreamOverlayStateController = dreamOverlayStateController;
+            mMediaComplication = mediaComplication;
+            mView.setOnClickListener(this::onClickMediaEntry);
+        }
+
+        @Override
+        protected void onViewAttached() {
+        }
+
+        @Override
+        protected void onViewDetached() {
+            removeMediaComplication();
+        }
+
+        private void onClickMediaEntry(View v) {
+            if (DEBUG) Log.d(TAG, "media entry complication tapped");
+
+            if (!mMediaComplicationAdded) {
+                addMediaComplication();
+            } else {
+                removeMediaComplication();
+            }
+        }
+
+        private void addMediaComplication() {
+            mView.setSelected(true);
+            mDreamOverlayStateController.addComplication(mMediaComplication);
+            mMediaComplicationAdded = true;
+        }
+
+        private void removeMediaComplication() {
+            mView.setSelected(false);
+            mDreamOverlayStateController.removeComplication(mMediaComplication);
+            mMediaComplicationAdded = false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
index 567bdbc..a981f25 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/SmartSpaceComplication.java
@@ -70,11 +70,7 @@
                 new BcSmartspaceDataPlugin.SmartspaceTargetListener() {
             @Override
             public void onSmartspaceTargetsUpdated(List<? extends Parcelable> targets) {
-                if (!targets.isEmpty()) {
-                    mDreamOverlayStateController.addComplication(mComplication);
-                } else {
-                    mDreamOverlayStateController.removeComplication(mComplication);
-                }
+                mDreamOverlayStateController.addComplication(mComplication);
             }
         };
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java
new file mode 100644
index 0000000..ed05daf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamMediaEntryComplicationComponent.java
@@ -0,0 +1,81 @@
+/*
+ * 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.dreams.complication.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.systemui.R;
+import com.android.systemui.dreams.complication.DreamMediaEntryComplication;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Named;
+import javax.inject.Scope;
+
+import dagger.Module;
+import dagger.Provides;
+import dagger.Subcomponent;
+
+/**
+ * Responsible for generating dependencies for the {@link DreamMediaEntryComplication}.
+ */
+@Subcomponent(modules = DreamMediaEntryComplicationComponent.DreamMediaEntryModule.class)
+@DreamMediaEntryComplicationComponent.DreamMediaEntryComplicationScope
+public interface DreamMediaEntryComplicationComponent {
+    /**
+     * Creates a view holder for the media entry complication.
+     */
+    DreamMediaEntryComplication.DreamMediaEntryViewHolder getViewHolder();
+
+    /**
+     * Scope of the media entry complication.
+     */
+    @Documented
+    @Retention(RUNTIME)
+    @Scope
+    @interface DreamMediaEntryComplicationScope {}
+
+    /**
+     * Factory that generates a {@link DreamMediaEntryComplicationComponent}.
+     */
+    @Subcomponent.Factory
+    interface Factory {
+        DreamMediaEntryComplicationComponent create();
+    }
+
+    /**
+     * Scoped injected values for the {@link DreamMediaEntryComplicationComponent}.
+     */
+    @Module
+    interface DreamMediaEntryModule {
+        String DREAM_MEDIA_ENTRY_VIEW = "dream_media_entry_view";
+
+        /**
+         * Provides the dream media entry view.
+         */
+        @Provides
+        @DreamMediaEntryComplicationScope
+        @Named(DREAM_MEDIA_ENTRY_VIEW)
+        static View provideMediaEntryView(LayoutInflater layoutInflater) {
+            return (View) layoutInflater.inflate(R.layout.dream_overlay_media_entry_chip, null);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
index eb07238..759d6ec 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -38,15 +38,19 @@
         },
         subcomponents = {
                 DreamHomeControlsComplicationComponent.class,
+                DreamMediaEntryComplicationComponent.class
         })
 public interface RegisteredComplicationsModule {
     String DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS = "time_complication_layout_params";
     String DREAM_SMARTSPACE_LAYOUT_PARAMS = "smartspace_layout_params";
     String DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS = "home_controls_chip_layout_params";
+    String DREAM_MEDIA_ENTRY_LAYOUT_PARAMS = "media_entry_layout_params";
 
     int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT = 1;
     int DREAM_SMARTSPACE_COMPLICATION_WEIGHT = 0;
+    int DREAM_MEDIA_COMPLICATION_WEIGHT = -1;
     int DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT = 1;
+    int DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT = 0;
 
     /**
      * Provides layout parameters for the clock time complication.
@@ -78,6 +82,21 @@
     }
 
     /**
+     * Provides layout parameters for the media entry complication.
+     */
+    @Provides
+    @Named(DREAM_MEDIA_ENTRY_LAYOUT_PARAMS)
+    static ComplicationLayoutParams provideMediaEntryLayoutParams(@Main Resources res) {
+        return new ComplicationLayoutParams(
+                res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width),
+                res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height),
+                ComplicationLayoutParams.POSITION_BOTTOM
+                        | ComplicationLayoutParams.POSITION_START,
+                ComplicationLayoutParams.DIRECTION_END,
+                DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT);
+    }
+
+    /**
      * Provides layout parameters for the smartspace complication.
      */
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 45237a3..78099d1f 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,12 +92,6 @@
     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);
   
     /**
@@ -186,6 +184,9 @@
     // 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);
+
     /***************************************/
     // 900 - media
     public static final ReleasedFlag MEDIA_TAP_TO_TRANSFER = new ReleasedFlag(900);
@@ -252,6 +253,9 @@
     // 1400 - columbus, b/242800729
     public static final UnreleasedFlag QUICK_TAP_IN_PCC = new UnreleasedFlag(1400);
 
+    // 1500 - chooser
+    public static final UnreleasedFlag CHOOSER_UNBUNDLED = new UnreleasedFlag(1500);
+
     // Pay no attention to the reflection behind the curtain.
     // ========================== Curtain ==========================
     // |                                                           |
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
index 9e2b7c7..a3dc779 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
@@ -50,7 +50,6 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 
@@ -61,6 +60,7 @@
 import java.util.Set;
 
 import javax.inject.Inject;
+import javax.inject.Provider;
 
 /** */
 @SysUISingleton
@@ -106,6 +106,8 @@
 
     protected volatile Context mContext;
 
+    private final Provider<LocalBluetoothManager> mBluetoothManagerProvider;
+
     private boolean mEnabled;
     private String mKeyboardName;
     private CachedBluetoothDeviceManager mCachedDeviceManager;
@@ -122,8 +124,9 @@
     private int mState;
 
     @Inject
-    public KeyboardUI(Context context) {
+    public KeyboardUI(Context context, Provider<LocalBluetoothManager> bluetoothManagerProvider) {
         super(context);
+        this.mBluetoothManagerProvider = bluetoothManagerProvider;
     }
 
     @Override
@@ -181,7 +184,7 @@
             return;
         }
 
-        LocalBluetoothManager bluetoothManager = Dependency.get(LocalBluetoothManager.class);
+        LocalBluetoothManager bluetoothManager = mBluetoothManagerProvider.get();
         if (bluetoothManager == null)  {
             if (DEBUG) {
                 Slog.e(TAG, "Failed to retrieve LocalBluetoothManager instance");
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 898959e..ee5ef99 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;
@@ -271,6 +275,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);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 9ecfb75..8eca1ba 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -282,7 +282,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
@@ -574,7 +575,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.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 70e0d5f..dc03436 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -73,6 +73,8 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.util.EventLog;
+import android.util.Log;
+import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.view.IRemoteAnimationFinishedCallback;
@@ -104,7 +106,6 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.KeyguardViewController;
 import com.android.keyguard.ViewMediatorCallback;
-import com.android.keyguard.logging.KeyguardViewMediatorLogger;
 import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.DejankUtils;
@@ -512,7 +513,8 @@
         public void onKeyguardVisibilityChanged(boolean showing) {
             synchronized (KeyguardViewMediator.this) {
                 if (!showing && mPendingPinLock) {
-                    mLogger.logPinLockRequestedStartingKeyguard();
+                    Log.i(TAG, "PIN lock requested, starting keyguard");
+
                     // Bring the keyguard back in order to show the PIN lock
                     mPendingPinLock = false;
                     doKeyguardLocked(null);
@@ -522,7 +524,7 @@
 
         @Override
         public void onUserSwitching(int userId) {
-            mLogger.logUserSwitching(userId);
+            if (DEBUG) Log.d(TAG, String.format("onUserSwitching %d", userId));
             // Note that the mLockPatternUtils user has already been updated from setCurrentUser.
             // We need to force a reset of the views, since lockNow (called by
             // ActivityManagerService) will not reconstruct the keyguard if it is already showing.
@@ -540,7 +542,7 @@
 
         @Override
         public void onUserSwitchComplete(int userId) {
-            mLogger.logOnUserSwitchComplete(userId);
+            if (DEBUG) Log.d(TAG, String.format("onUserSwitchComplete %d", userId));
             if (userId != UserHandle.USER_SYSTEM) {
                 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
                 // Don't try to dismiss if the user has Pin/Pattern/Password set
@@ -568,7 +570,8 @@
         public void onSimStateChanged(int subId, int slotId, int simState) {
 
             if (DEBUG_SIM_STATES) {
-                mLogger.logOnSimStateChanged(subId, slotId, String.valueOf(simState));
+                Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
+                        + ",state=" + simState + ")");
             }
 
             int size = mKeyguardStateCallbacks.size();
@@ -577,7 +580,7 @@
                 try {
                     mKeyguardStateCallbacks.get(i).onSimSecureStateChanged(simPinSecure);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnSimSecureStateChanged(e);
+                    Slog.w(TAG, "Failed to call onSimSecureStateChanged", e);
                     if (e instanceof DeadObjectException) {
                         mKeyguardStateCallbacks.remove(i);
                     }
@@ -600,9 +603,9 @@
                     synchronized (KeyguardViewMediator.this) {
                         if (shouldWaitForProvisioning()) {
                             if (!mShowing) {
-                                if (DEBUG_SIM_STATES) {
-                                    mLogger.logIccAbsentIsNotShowing();
-                                }
+                                if (DEBUG_SIM_STATES) Log.d(TAG, "ICC_ABSENT isn't showing,"
+                                        + " we need to show the keyguard since the "
+                                        + "device isn't provisioned yet.");
                                 doKeyguardLocked(null);
                             } else {
                                 resetStateLocked();
@@ -612,9 +615,8 @@
                             // MVNO SIMs can become transiently NOT_READY when switching networks,
                             // so we should only lock when they are ABSENT.
                             if (lastSimStateWasLocked) {
-                                if (DEBUG_SIM_STATES) {
-                                    mLogger.logSimMovedToAbsent();
-                                }
+                                if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to ABSENT when the "
+                                        + "previous state was locked. Reset the state.");
                                 resetStateLocked();
                             }
                             mSimWasLocked.append(slotId, false);
@@ -627,9 +629,9 @@
                         mSimWasLocked.append(slotId, true);
                         mPendingPinLock = true;
                         if (!mShowing) {
-                            if (DEBUG_SIM_STATES) {
-                                mLogger.logIntentValueIccLocked();
-                            }
+                            if (DEBUG_SIM_STATES) Log.d(TAG,
+                                    "INTENT_VALUE_ICC_LOCKED and keygaurd isn't "
+                                    + "showing; need to show keyguard so user can enter sim pin");
                             doKeyguardLocked(null);
                         } else {
                             resetStateLocked();
@@ -639,36 +641,29 @@
                 case TelephonyManager.SIM_STATE_PERM_DISABLED:
                     synchronized (KeyguardViewMediator.this) {
                         if (!mShowing) {
-                            if (DEBUG_SIM_STATES) {
-                                mLogger.logPermDisabledKeyguardNotShowing();
-                            }
+                            if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
+                                  + "keygaurd isn't showing.");
                             doKeyguardLocked(null);
                         } else {
-                            if (DEBUG_SIM_STATES) {
-                                mLogger.logPermDisabledResetStateLocked();
-                            }
+                            if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED, resetStateLocked to"
+                                  + "show permanently disabled message in lockscreen.");
                             resetStateLocked();
                         }
                     }
                     break;
                 case TelephonyManager.SIM_STATE_READY:
                     synchronized (KeyguardViewMediator.this) {
-                        if (DEBUG_SIM_STATES) {
-                            mLogger.logReadyResetState(mShowing);
-                        }
+                        if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
                         if (mShowing && mSimWasLocked.get(slotId, false)) {
-                            if (DEBUG_SIM_STATES) {
-                                mLogger.logSimMovedToReady();
-                            }
+                            if (DEBUG_SIM_STATES) Log.d(TAG, "SIM moved to READY when the "
+                                    + "previously was locked. Reset the state.");
                             mSimWasLocked.append(slotId, false);
                             resetStateLocked();
                         }
                     }
                     break;
                 default:
-                    if (DEBUG_SIM_STATES) {
-                        mLogger.logUnspecifiedSimState(simState);
-                    }
+                    if (DEBUG_SIM_STATES) Log.v(TAG, "Unspecific state: " + simState);
                     break;
             }
         }
@@ -713,7 +708,7 @@
             if (targetUserId != ActivityManager.getCurrentUser()) {
                 return;
             }
-            mLogger.logKeyguardDone();
+            if (DEBUG) Log.d(TAG, "keyguardDone");
             tryKeyguardDone();
         }
 
@@ -732,7 +727,7 @@
         @Override
         public void keyguardDonePending(boolean strongAuth, int targetUserId) {
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardDonePending");
-            mLogger.logKeyguardDonePending();
+            if (DEBUG) Log.d(TAG, "keyguardDonePending");
             if (targetUserId != ActivityManager.getCurrentUser()) {
                 Trace.endSection();
                 return;
@@ -751,7 +746,7 @@
         @Override
         public void keyguardGone() {
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone");
-            mLogger.logKeyguardGone();
+            if (DEBUG) Log.d(TAG, "keyguardGone");
             mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false);
             mKeyguardDisplayManager.hide();
             Trace.endSection();
@@ -837,7 +832,8 @@
 
                 @Override
                 public void onLaunchAnimationCancelled() {
-                    mLogger.logOccludeLaunchAnimationCancelled(mOccluded);
+                    Log.d(TAG, "Occlude launch animation cancelled. Occluded state is now: "
+                            + mOccluded);
                 }
 
                 @Override
@@ -857,7 +853,8 @@
                 @Override
                 public void setLaunchContainer(@NonNull ViewGroup launchContainer) {
                     // No-op, launch container is always the shade.
-                    mLogger.logActivityLaunchAnimatorLaunchContainerChanged();
+                    Log.wtf(TAG, "Someone tried to change the launch container for the "
+                            + "ActivityLaunchAnimator, which should never happen.");
                 }
 
                 @NonNull
@@ -890,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
@@ -908,7 +985,8 @@
                     }
 
                     setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
-                    mLogger.logUnoccludeAnimationCancelled(mOccluded);
+                    Log.d(TAG, "Unocclude animation cancelled. Occluded state is now: "
+                            + mOccluded);
                 }
 
                 @Override
@@ -916,11 +994,12 @@
                         RemoteAnimationTarget[] wallpapers,
                         RemoteAnimationTarget[] nonApps,
                         IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
-                    mLogger.logUnoccludeAnimatorOnAnimationStart();
+                    Log.d(TAG, "UnoccludeAnimator#onAnimationStart. Set occluded = false.");
                     setOccluded(false /* isOccluded */, true /* animate */);
 
                     if (apps == null || apps.length == 0 || apps[0] == null) {
-                        mLogger.logNoAppsProvidedToUnoccludeRunner();
+                        Log.d(TAG, "No apps provided to unocclude runner; "
+                                + "skipping animation and unoccluding.");
                         finishedCallback.onAnimationFinished();
                         return;
                     }
@@ -1008,7 +1087,6 @@
     private ScreenOnCoordinator mScreenOnCoordinator;
 
     private Lazy<ActivityLaunchAnimator> mActivityLaunchAnimator;
-    private KeyguardViewMediatorLogger mLogger;
 
     /**
      * Injected constructor. See {@link KeyguardModule}.
@@ -1037,8 +1115,7 @@
             InteractionJankMonitor interactionJankMonitor,
             DreamOverlayStateController dreamOverlayStateController,
             Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
-            Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
-            KeyguardViewMediatorLogger logger) {
+            Lazy<ActivityLaunchAnimator> activityLaunchAnimator) {
         super(context);
         mFalsingCollector = falsingCollector;
         mLockPatternUtils = lockPatternUtils;
@@ -1081,7 +1158,6 @@
         mDreamOverlayStateController = dreamOverlayStateController;
 
         mActivityLaunchAnimator = activityLaunchAnimator;
-        mLogger = logger;
 
         mPowerButtonY = context.getResources().getDimensionPixelSize(
                 R.dimen.physical_power_button_center_screen_location_y);
@@ -1145,21 +1221,21 @@
             mLockSoundId = mLockSounds.load(soundPath, 1);
         }
         if (soundPath == null || mLockSoundId == 0) {
-            mLogger.logFailedLoadLockSound(soundPath);
+            Log.w(TAG, "failed to load lock sound from " + soundPath);
         }
         soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
         if (soundPath != null) {
             mUnlockSoundId = mLockSounds.load(soundPath, 1);
         }
         if (soundPath == null || mUnlockSoundId == 0) {
-            mLogger.logFailedLoadUnlockSound(soundPath);
+            Log.w(TAG, "failed to load unlock sound from " + soundPath);
         }
         soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND);
         if (soundPath != null) {
             mTrustedSoundId = mLockSounds.load(soundPath, 1);
         }
         if (soundPath == null || mTrustedSoundId == 0) {
-            mLogger.logFailedLoadTrustedSound(soundPath);
+            Log.w(TAG, "failed to load trusted sound from " + soundPath);
         }
 
         int lockSoundDefaultAttenuation = mContext.getResources().getInteger(
@@ -1188,7 +1264,7 @@
 
     private void handleSystemReady() {
         synchronized (this) {
-            mLogger.logOnSystemReady();
+            if (DEBUG) Log.d(TAG, "onSystemReady");
             mSystemReady = true;
             doKeyguardLocked(null);
             mUpdateMonitor.registerCallback(mUpdateCallback);
@@ -1206,7 +1282,7 @@
      * {@link WindowManagerPolicyConstants#OFF_BECAUSE_OF_TIMEOUT}.
      */
     public void onStartedGoingToSleep(@WindowManagerPolicyConstants.OffReason int offReason) {
-        mLogger.logOnStartedGoingToSleep(offReason);
+        if (DEBUG) Log.d(TAG, "onStartedGoingToSleep(" + offReason + ")");
         synchronized (this) {
             mDeviceInteractive = false;
             mPowerGestureIntercepted = false;
@@ -1222,11 +1298,11 @@
             long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());
             mLockLater = false;
             if (mExitSecureCallback != null) {
-                mLogger.logPendingExitSecureCallbackCancelled();
+                if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
                 try {
                     mExitSecureCallback.onKeyguardExitResult(false);
                 } catch (RemoteException e) {
-                    mLogger.logFailedOnKeyguardExitResultFalse(e);
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                 }
                 mExitSecureCallback = null;
                 if (!mExternallyEnabled) {
@@ -1271,7 +1347,7 @@
      */
     public void onFinishedGoingToSleep(
             @WindowManagerPolicyConstants.OffReason int offReason, boolean cameraGestureTriggered) {
-        mLogger.logOnFinishedGoingToSleep(offReason);
+        if (DEBUG) Log.d(TAG, "onFinishedGoingToSleep(" + offReason + ")");
         synchronized (this) {
             mDeviceInteractive = false;
             mGoingToSleep = false;
@@ -1329,7 +1405,13 @@
             //   - The screen off animation is cancelled by the device waking back up. We will call
             //     maybeHandlePendingLock from KeyguardViewMediator#onStartedWakingUp.
             if (mScreenOffAnimationController.isKeyguardShowDelayed()) {
-                mLogger.logMaybeHandlePendingLockNotHandling();
+                if (DEBUG) {
+                    Log.d(TAG, "#maybeHandlePendingLock: not handling because the screen off "
+                            + "animation's isKeyguardShowDelayed() returned true. This should be "
+                            + "handled soon by #onStartedWakingUp, or by the end actions of the "
+                            + "screen off animation.");
+                }
+
                 return;
             }
 
@@ -1339,11 +1421,18 @@
             // StatusBar#finishKeyguardFadingAway, which is always responsible for setting
             // isKeyguardGoingAway to false.
             if (mKeyguardStateController.isKeyguardGoingAway()) {
-                mLogger.logMaybeHandlePendingLockKeyguardGoingAway();
+                if (DEBUG) {
+                    Log.d(TAG, "#maybeHandlePendingLock: not handling because the keyguard is "
+                            + "going away. This should be handled shortly by "
+                            + "StatusBar#finishKeyguardFadingAway.");
+                }
+
                 return;
             }
 
-            mLogger.logMaybeHandlePendingLockHandling();
+            if (DEBUG) {
+                Log.d(TAG, "#maybeHandlePendingLock: handling pending lock; locking keyguard.");
+            }
 
             doKeyguardLocked(null);
             setPendingLock(false);
@@ -1412,7 +1501,8 @@
         PendingIntent sender = PendingIntent.getBroadcast(mContext,
                 0, intent, PendingIntent.FLAG_CANCEL_CURRENT |  PendingIntent.FLAG_IMMUTABLE);
         mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
-        mLogger.logSetAlarmToTurnOffKeyguard(mDelayedShowingSequence);
+        if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+                         + mDelayedShowingSequence);
         doKeyguardLaterForChildProfilesLocked();
     }
 
@@ -1472,7 +1562,7 @@
             mAnimatingScreenOff = false;
             cancelDoKeyguardLaterLocked();
             cancelDoKeyguardForChildProfilesLocked();
-            mLogger.logOnStartedWakingUp(mDelayedShowingSequence);
+            if (DEBUG) Log.d(TAG, "onStartedWakingUp, seq = " + mDelayedShowingSequence);
             notifyStartedWakingUp();
         }
         mUpdateMonitor.dispatchStartedWakingUp();
@@ -1532,35 +1622,37 @@
      */
     public void setKeyguardEnabled(boolean enabled) {
         synchronized (this) {
-            mLogger.logSetKeyguardEnabled(enabled);
+            if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
 
             mExternallyEnabled = enabled;
 
             if (!enabled && mShowing) {
                 if (mExitSecureCallback != null) {
-                    mLogger.logIgnoreVerifyUnlockRequest();
+                    if (DEBUG) Log.d(TAG, "in process of verifyUnlock request, ignoring");
                     // we're in the process of handling a request to verify the user
                     // can get past the keyguard. ignore extraneous requests to disable / re-enable
                     return;
                 }
 
                 // hiding keyguard that is showing, remember to reshow later
-                mLogger.logRememberToReshowLater();
+                if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
+                        + "disabling status bar expansion");
                 mNeedToReshowWhenReenabled = true;
                 updateInputRestrictedLocked();
                 hideLocked();
             } else if (enabled && mNeedToReshowWhenReenabled) {
                 // re-enabled after previously hidden, reshow
-                mLogger.logPreviouslyHiddenReshow();
+                if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
+                        + "status bar expansion");
                 mNeedToReshowWhenReenabled = false;
                 updateInputRestrictedLocked();
 
                 if (mExitSecureCallback != null) {
-                    mLogger.logOnKeyguardExitResultFalseResetting();
+                    if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
                     try {
                         mExitSecureCallback.onKeyguardExitResult(false);
                     } catch (RemoteException e) {
-                        mLogger.logFailedToCallOnKeyguardExitResultFalse(e);
+                        Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                     }
                     mExitSecureCallback = null;
                     resetStateLocked();
@@ -1572,7 +1664,7 @@
                     // and causing an ANR).
                     mWaitingUntilKeyguardVisible = true;
                     mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_DRAWING, KEYGUARD_DONE_DRAWING_TIMEOUT_MS);
-                    mLogger.logWaitingUntilKeyguardVisibleIsFalse();
+                    if (DEBUG) Log.d(TAG, "waiting until mWaitingUntilKeyguardVisible is false");
                     while (mWaitingUntilKeyguardVisible) {
                         try {
                             wait();
@@ -1580,7 +1672,7 @@
                             Thread.currentThread().interrupt();
                         }
                     }
-                    mLogger.logDoneWaitingUntilKeyguardVisible();
+                    if (DEBUG) Log.d(TAG, "done waiting for mWaitingUntilKeyguardVisible");
                 }
             }
         }
@@ -1592,31 +1684,31 @@
     public void verifyUnlock(IKeyguardExitCallback callback) {
         Trace.beginSection("KeyguardViewMediator#verifyUnlock");
         synchronized (this) {
-            mLogger.logVerifyUnlock();
+            if (DEBUG) Log.d(TAG, "verifyUnlock");
             if (shouldWaitForProvisioning()) {
                 // don't allow this api when the device isn't provisioned
-                mLogger.logIgnoreUnlockDeviceNotProvisioned();
+                if (DEBUG) Log.d(TAG, "ignoring because device isn't provisioned");
                 try {
                     callback.onKeyguardExitResult(false);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnKeyguardExitResultFalse(e);
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                 }
             } else if (mExternallyEnabled) {
                 // this only applies when the user has externally disabled the
                 // keyguard.  this is unexpected and means the user is not
                 // using the api properly.
-                mLogger.logVerifyUnlockCalledNotExternallyDisabled();
+                Log.w(TAG, "verifyUnlock called when not externally disabled");
                 try {
                     callback.onKeyguardExitResult(false);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnKeyguardExitResultFalse(e);
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                 }
             } else if (mExitSecureCallback != null) {
                 // already in progress with someone else
                 try {
                     callback.onKeyguardExitResult(false);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnKeyguardExitResultFalse(e);
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                 }
             } else if (!isSecure()) {
 
@@ -1628,7 +1720,7 @@
                 try {
                     callback.onKeyguardExitResult(true);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnKeyguardExitResultFalse(e);
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                 }
             } else {
 
@@ -1637,7 +1729,7 @@
                 try {
                     callback.onKeyguardExitResult(false);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnKeyguardExitResultFalse(e);
+                    Slog.w(TAG, "Failed to call onKeyguardExitResult(false)", e);
                 }
             }
         }
@@ -1655,8 +1747,10 @@
      * Notify us when the keyguard is occluded by another window
      */
     public void setOccluded(boolean isOccluded, boolean animate) {
+        Log.d(TAG, "setOccluded(" + isOccluded + ")");
+
         Trace.beginSection("KeyguardViewMediator#setOccluded");
-        mLogger.logSetOccluded(isOccluded);
+        if (DEBUG) Log.d(TAG, "setOccluded " + isOccluded);
         mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_TRANSITION_FROM_AOD);
         mHandler.removeMessages(SET_OCCLUDED);
         Message msg = mHandler.obtainMessage(SET_OCCLUDED, isOccluded ? 1 : 0, animate ? 1 : 0);
@@ -1668,6 +1762,10 @@
         return mOccludeAnimationRunner;
     }
 
+    public IRemoteAnimationRunner getOccludeByDreamAnimationRunner() {
+        return mOccludeByDreamAnimationRunner;
+    }
+
     public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
         return mUnoccludeAnimationRunner;
     }
@@ -1685,7 +1783,7 @@
      */
     private void handleSetOccluded(boolean isOccluded, boolean animate) {
         Trace.beginSection("KeyguardViewMediator#handleSetOccluded");
-        mLogger.logHandleSetOccluded(isOccluded);
+        Log.d(TAG, "handleSetOccluded(" + isOccluded + ")");
         synchronized (KeyguardViewMediator.this) {
             if (mHiding && isOccluded) {
                 // We're in the process of going away but WindowManager wants to show a
@@ -1742,7 +1840,7 @@
                 try {
                     callback.onInputRestrictedStateChanged(inputRestricted);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnDeviceProvisioned(e);
+                    Slog.w(TAG, "Failed to call onDeviceProvisioned", e);
                     if (e instanceof DeadObjectException) {
                         mKeyguardStateCallbacks.remove(callback);
                     }
@@ -1757,7 +1855,8 @@
     private void doKeyguardLocked(Bundle options) {
         // if another app is disabling us, don't show
         if (!mExternallyEnabled) {
-            mLogger.logDoKeyguardNotShowingExternallyDisabled();
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because externally disabled");
+
             mNeedToReshowWhenReenabled = true;
             return;
         }
@@ -1766,7 +1865,7 @@
         // to account for the hiding animation which results in a delay and discrepancy
         // between flags
         if (mShowing && mKeyguardViewControllerLazy.get().isShowing()) {
-            mLogger.logDoKeyguardNotShowingAlreadyShowing();
+            if (DEBUG) Log.d(TAG, "doKeyguard: not showing because it is already showing");
             resetStateLocked();
             return;
         }
@@ -1785,19 +1884,20 @@
                     || ((absent || disabled) && requireSim);
 
             if (!lockedOrMissing && shouldWaitForProvisioning()) {
-                mLogger.logDoKeyguardNotShowingDeviceNotProvisioned();
+                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
+                        + " and the sim is not locked or missing");
                 return;
             }
 
             boolean forceShow = options != null && options.getBoolean(OPTION_FORCE_SHOW, false);
             if (mLockPatternUtils.isLockScreenDisabled(KeyguardUpdateMonitor.getCurrentUser())
                     && !lockedOrMissing && !forceShow) {
-                mLogger.logDoKeyguardNotShowingLockScreenOff();
+                if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
                 return;
             }
         }
 
-        mLogger.logDoKeyguardShowingLockScreen();
+        if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
         showLocked(options);
     }
 
@@ -1835,23 +1935,32 @@
      * @see #handleReset
      */
     private void resetStateLocked() {
-        mLogger.logResetStateLocked();
+        if (DEBUG) Log.e(TAG, "resetStateLocked");
         Message msg = mHandler.obtainMessage(RESET);
         mHandler.sendMessage(msg);
     }
 
+    /**
+     * Send message to keyguard telling it to verify unlock
+     * @see #handleVerifyUnlock()
+     */
+    private void verifyUnlockLocked() {
+        if (DEBUG) Log.d(TAG, "verifyUnlockLocked");
+        mHandler.sendEmptyMessage(VERIFY_UNLOCK);
+    }
+
     private void notifyStartedGoingToSleep() {
-        mLogger.logNotifyStartedGoingToSleep();
+        if (DEBUG) Log.d(TAG, "notifyStartedGoingToSleep");
         mHandler.sendEmptyMessage(NOTIFY_STARTED_GOING_TO_SLEEP);
     }
 
     private void notifyFinishedGoingToSleep() {
-        mLogger.logNotifyFinishedGoingToSleep();
+        if (DEBUG) Log.d(TAG, "notifyFinishedGoingToSleep");
         mHandler.sendEmptyMessage(NOTIFY_FINISHED_GOING_TO_SLEEP);
     }
 
     private void notifyStartedWakingUp() {
-        mLogger.logNotifyStartedWakingUp();
+        if (DEBUG) Log.d(TAG, "notifyStartedWakingUp");
         mHandler.sendEmptyMessage(NOTIFY_STARTED_WAKING_UP);
     }
 
@@ -1861,7 +1970,7 @@
      */
     private void showLocked(Bundle options) {
         Trace.beginSection("KeyguardViewMediator#showLocked acquiring mShowKeyguardWakeLock");
-        mLogger.logShowLocked();
+        if (DEBUG) Log.d(TAG, "showLocked");
         // ensure we stay awake until we are finished displaying the keyguard
         mShowKeyguardWakeLock.acquire();
         Message msg = mHandler.obtainMessage(SHOW, options);
@@ -1878,7 +1987,7 @@
      */
     private void hideLocked() {
         Trace.beginSection("KeyguardViewMediator#hideLocked");
-        mLogger.logHideLocked();
+        if (DEBUG) Log.d(TAG, "hideLocked");
         Message msg = mHandler.obtainMessage(HIDE);
         mHandler.sendMessage(msg);
         Trace.endSection();
@@ -1957,7 +2066,8 @@
         public void onReceive(Context context, Intent intent) {
             if (DELAYED_KEYGUARD_ACTION.equals(intent.getAction())) {
                 final int sequence = intent.getIntExtra("seq", 0);
-                mLogger.logReceivedDelayedKeyguardAction(sequence, mDelayedShowingSequence);
+                if (DEBUG) Log.d(TAG, "received DELAYED_KEYGUARD_ACTION with seq = "
+                        + sequence + ", mDelayedShowingSequence = " + mDelayedShowingSequence);
                 synchronized (KeyguardViewMediator.this) {
                     if (mDelayedShowingSequence == sequence) {
                         doKeyguardLocked(null);
@@ -1990,7 +2100,7 @@
 
     private void keyguardDone() {
         Trace.beginSection("KeyguardViewMediator#keyguardDone");
-        mLogger.logKeyguardDone();
+        if (DEBUG) Log.d(TAG, "keyguardDone()");
         userActivity();
         EventLog.writeEvent(70000, 2);
         Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
@@ -2082,7 +2192,7 @@
                 case KEYGUARD_DONE_PENDING_TIMEOUT:
                     Trace.beginSection("KeyguardViewMediator#handleMessage"
                             + " KEYGUARD_DONE_PENDING_TIMEOUT");
-                    mLogger.logTimeoutWhileActivityDrawn();
+                    Log.w(TAG, "Timeout while waiting for activity drawn!");
                     Trace.endSection();
                     break;
                 case SYSTEM_READY:
@@ -2093,15 +2203,14 @@
     };
 
     private void tryKeyguardDone() {
-        mLogger.logTryKeyguardDonePending(
-                mKeyguardDonePending,
-                mHideAnimationRun,
-                mHideAnimationRunning
-        );
+        if (DEBUG) {
+            Log.d(TAG, "tryKeyguardDone: pending - " + mKeyguardDonePending + ", animRan - "
+                    + mHideAnimationRun + " animRunning - " + mHideAnimationRunning);
+        }
         if (!mKeyguardDonePending && mHideAnimationRun && !mHideAnimationRunning) {
             handleKeyguardDone();
         } else if (!mHideAnimationRun) {
-            mLogger.logTryKeyguardDonePreHideAnimation();
+            if (DEBUG) Log.d(TAG, "tryKeyguardDone: starting pre-hide animation");
             mHideAnimationRun = true;
             mHideAnimationRunning = true;
             mKeyguardViewControllerLazy.get()
@@ -2121,14 +2230,14 @@
                 mLockPatternUtils.getDevicePolicyManager().reportKeyguardDismissed(currentUser);
             }
         });
-        mLogger.logHandleKeyguardDone();
+        if (DEBUG) Log.d(TAG, "handleKeyguardDone");
         synchronized (this) {
             resetKeyguardDonePendingLocked();
         }
 
         if (mGoingToSleep) {
             mUpdateMonitor.clearBiometricRecognizedWhenKeyguardDone(currentUser);
-            mLogger.logDeviceGoingToSleep();
+            Log.i(TAG, "Device is going to sleep, aborting keyguardDone");
             return;
         }
         setPendingLock(false); // user may have authenticated during the screen off animation
@@ -2136,7 +2245,7 @@
             try {
                 mExitSecureCallback.onKeyguardExitResult(true /* authenciated */);
             } catch (RemoteException e) {
-                mLogger.logFailedToCallOnKeyguardExitResultTrue(e);
+                Slog.w(TAG, "Failed to call onKeyguardExitResult()", e);
             }
 
             mExitSecureCallback = null;
@@ -2179,9 +2288,9 @@
     private void handleKeyguardDoneDrawing() {
         Trace.beginSection("KeyguardViewMediator#handleKeyguardDoneDrawing");
         synchronized(this) {
-            mLogger.logHandleKeyguardDoneDrawing();
+            if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing");
             if (mWaitingUntilKeyguardVisible) {
-                mLogger.logHandleKeyguardDoneDrawingNotifyingKeyguardVisible();
+                if (DEBUG) Log.d(TAG, "handleKeyguardDoneDrawing: notifying mWaitingUntilKeyguardVisible");
                 mWaitingUntilKeyguardVisible = false;
                 notifyAll();
 
@@ -2231,11 +2340,12 @@
 
     private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
         mUiBgExecutor.execute(() -> {
-            mLogger.logUpdateActivityLockScreenState(showing, aodShowing);
+            if (DEBUG) {
+                Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
+            }
             try {
                 ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
             } catch (RemoteException e) {
-                mLogger.logFailedToCallSetLockScreenShown(e);
             }
         });
     }
@@ -2252,10 +2362,10 @@
         }
         synchronized (KeyguardViewMediator.this) {
             if (!mSystemReady) {
-                mLogger.logIgnoreHandleShow();
+                if (DEBUG) Log.d(TAG, "ignoring handleShow because system is not ready.");
                 return;
             } else {
-                mLogger.logHandleShow();
+                if (DEBUG) Log.d(TAG, "handleShow");
             }
 
             mHiding = false;
@@ -2287,7 +2397,7 @@
         @Override
         public void run() {
             Trace.beginSection("KeyguardViewMediator.mKeyGuardGoingAwayRunnable");
-            mLogger.logKeyguardGoingAway();
+            if (DEBUG) Log.d(TAG, "keyguardGoingAway");
             mKeyguardViewControllerLazy.get().keyguardGoingAway();
 
             int flags = 0;
@@ -2331,7 +2441,7 @@
                 try {
                     ActivityTaskManager.getService().keyguardGoingAway(keyguardFlag);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallKeyguardGoingAway(keyguardFlag, e);
+                    Log.e(TAG, "Error while calling WindowManager", e);
                 }
             });
             Trace.endSection();
@@ -2339,7 +2449,7 @@
     };
 
     private final Runnable mHideAnimationFinishedRunnable = () -> {
-        mLogger.logHideAnimationFinishedRunnable();
+        Log.e(TAG, "mHideAnimationFinishedRunnable#run");
         mHideAnimationRunning = false;
         tryKeyguardDone();
     };
@@ -2359,14 +2469,14 @@
         }
 
         synchronized (KeyguardViewMediator.this) {
-            mLogger.logHandleHide();
+            if (DEBUG) Log.d(TAG, "handleHide");
 
             if (mustNotUnlockCurrentUser()) {
                 // In split system user mode, we never unlock system user. The end user has to
                 // switch to another user.
                 // TODO: We should stop it early by disabling the swipe up flow. Right now swipe up
                 // still completes and makes the screen blank.
-                mLogger.logSplitSystemUserQuitUnlocking();
+                if (DEBUG) Log.d(TAG, "Split system user, quit unlocking.");
                 mKeyguardExitAnimationRunner = null;
                 return;
             }
@@ -2398,7 +2508,8 @@
             RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers,
             RemoteAnimationTarget[] nonApps, IRemoteAnimationFinishedCallback finishedCallback) {
         Trace.beginSection("KeyguardViewMediator#handleStartKeyguardExitAnimation");
-        mLogger.logHandleStartKeyguardExitAnimation(startTime, fadeoutDuration);
+        Log.d(TAG, "handleStartKeyguardExitAnimation startTime=" + startTime
+                + " fadeoutDuration=" + fadeoutDuration);
         synchronized (KeyguardViewMediator.this) {
 
             // Tell ActivityManager that we canceled the keyguard animation if
@@ -2414,7 +2525,7 @@
                     try {
                         finishedCallback.onAnimationFinished();
                     } catch (RemoteException e) {
-                        mLogger.logFailedToCallOnAnimationFinished(e);
+                        Slog.w(TAG, "Failed to call onAnimationFinished", e);
                     }
                 }
                 setShowingLocked(mShowing, true /* force */);
@@ -2437,7 +2548,7 @@
                                 try {
                                     finishedCallback.onAnimationFinished();
                                 } catch (RemoteException e) {
-                                    mLogger.logFailedToCallOnAnimationFinished(e);
+                                    Slog.w(TAG, "Failed to call onAnimationFinished", e);
                                 }
                                 onKeyguardExitFinished();
                                 mKeyguardViewControllerLazy.get().hide(0 /* startTime */,
@@ -2456,7 +2567,7 @@
                     runner.onAnimationStart(WindowManager.TRANSIT_KEYGUARD_GOING_AWAY, apps,
                             wallpapers, nonApps, callback);
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnAnimationStart(e);
+                    Slog.w(TAG, "Failed to call onAnimationStart", e);
                 }
 
             // When remaining on the shade, there's no need to do a fancy remote animation,
@@ -2520,7 +2631,7 @@
                             try {
                                 finishedCallback.onAnimationFinished();
                             } catch (RemoteException e) {
-                                mLogger.logFailedToCallOnAnimationFinished(e);
+                                Slog.e(TAG, "RemoteException");
                             } finally {
                                 mInteractionJankMonitor.end(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                             }
@@ -2531,7 +2642,7 @@
                             try {
                                 finishedCallback.onAnimationFinished();
                             } catch (RemoteException e) {
-                                mLogger.logFailedToCallOnAnimationFinished(e);
+                                Slog.e(TAG, "RemoteException");
                             } finally {
                                 mInteractionJankMonitor.cancel(CUJ_LOCKSCREEN_UNLOCK_ANIMATION);
                             }
@@ -2600,9 +2711,11 @@
      * @param cancelled {@code true} if the animation was cancelled before it finishes.
      */
     public void onKeyguardExitRemoteAnimationFinished(boolean cancelled) {
-        mLogger.logOnKeyguardExitRemoteAnimationFinished();
+        Log.d(TAG, "onKeyguardExitRemoteAnimationFinished");
         if (!mSurfaceBehindRemoteAnimationRunning && !mSurfaceBehindRemoteAnimationRequested) {
-            mLogger.logSkipOnKeyguardExitRemoteAnimationFinished(cancelled, false, false);
+            Log.d(TAG, "skip onKeyguardExitRemoteAnimationFinished cancelled=" + cancelled
+                    + " surfaceAnimationRunning=" + mSurfaceBehindRemoteAnimationRunning
+                    + " surfaceAnimationRequested=" + mSurfaceBehindRemoteAnimationRequested);
             return;
         }
 
@@ -2616,13 +2729,13 @@
             onKeyguardExitFinished();
 
             if (mKeyguardStateController.isDismissingFromSwipe() || wasShowing) {
-                mLogger.logOnKeyguardExitRemoteAnimationFinishedHideKeyguardView();
+                Log.d(TAG, "onKeyguardExitRemoteAnimationFinished"
+                        + "#hideKeyguardViewAfterRemoteAnimation");
                 mKeyguardUnlockAnimationControllerLazy.get().hideKeyguardViewAfterRemoteAnimation();
             } else {
-                mLogger.logSkipHideKeyguardViewAfterRemoteAnimation(
-                        mKeyguardStateController.isDismissingFromSwipe(),
-                        wasShowing
-                );
+                Log.d(TAG, "skip hideKeyguardViewAfterRemoteAnimation"
+                        + " dismissFromSwipe=" + mKeyguardStateController.isDismissingFromSwipe()
+                        + " wasShowing=" + wasShowing);
             }
 
             finishSurfaceBehindRemoteAnimation(cancelled);
@@ -2719,7 +2832,7 @@
         }
 
         if (mStatusBarManager == null) {
-            mLogger.logCouldNotGetStatusBarManager();
+            Log.w(TAG, "Could not get status bar manager");
         } else {
             // Disable aspects of the system/status/navigation bars that must not be re-enabled by
             // windows that appear on top, ever
@@ -2737,13 +2850,12 @@
                 }
                 flags |= StatusBarManager.DISABLE_RECENT;
             }
-            mLogger.logAdjustStatusBarLocked(
-                    mShowing,
-                    mOccluded,
-                    isSecure(),
-                    forceHideHomeRecentsButtons,
-                    Integer.toHexString(flags)
-            );
+
+            if (DEBUG) {
+                Log.d(TAG, "adjustStatusBarLocked: mShowing=" + mShowing + " mOccluded=" + mOccluded
+                        + " isSecure=" + isSecure() + " force=" + forceHideHomeRecentsButtons
+                        +  " --> flags=0x" + Integer.toHexString(flags));
+            }
 
             mStatusBarManager.disable(flags);
         }
@@ -2755,7 +2867,7 @@
      */
     private void handleReset() {
         synchronized (KeyguardViewMediator.this) {
-            mLogger.logHandleReset();
+            if (DEBUG) Log.d(TAG, "handleReset");
             mKeyguardViewControllerLazy.get().reset(true /* hideBouncerWhenShowing */);
         }
     }
@@ -2767,7 +2879,7 @@
     private void handleVerifyUnlock() {
         Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
         synchronized (KeyguardViewMediator.this) {
-            mLogger.logHandleVerifyUnlock();
+            if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
             setShowingLocked(true);
             mKeyguardViewControllerLazy.get().dismissAndCollapse();
         }
@@ -2776,7 +2888,7 @@
 
     private void handleNotifyStartedGoingToSleep() {
         synchronized (KeyguardViewMediator.this) {
-            mLogger.logHandleNotifyStartedGoingToSleep();
+            if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep");
             mKeyguardViewControllerLazy.get().onStartedGoingToSleep();
         }
     }
@@ -2787,7 +2899,7 @@
      */
     private void handleNotifyFinishedGoingToSleep() {
         synchronized (KeyguardViewMediator.this) {
-            mLogger.logHandleNotifyFinishedGoingToSleep();
+            if (DEBUG) Log.d(TAG, "handleNotifyFinishedGoingToSleep");
             mKeyguardViewControllerLazy.get().onFinishedGoingToSleep();
         }
     }
@@ -2795,7 +2907,7 @@
     private void handleNotifyStartedWakingUp() {
         Trace.beginSection("KeyguardViewMediator#handleMotifyStartedWakingUp");
         synchronized (KeyguardViewMediator.this) {
-            mLogger.logHandleNotifyWakingUp();
+            if (DEBUG) Log.d(TAG, "handleNotifyWakingUp");
             mKeyguardViewControllerLazy.get().onStartedWakingUp();
         }
         Trace.endSection();
@@ -3061,7 +3173,7 @@
                 try {
                     callback.onShowingStateChanged(showing, KeyguardUpdateMonitor.getCurrentUser());
                 } catch (RemoteException e) {
-                    mLogger.logFailedToCallOnShowingStateChanged(e);
+                    Slog.w(TAG, "Failed to call onShowingStateChanged", e);
                     if (e instanceof DeadObjectException) {
                         mKeyguardStateCallbacks.remove(callback);
                     }
@@ -3080,7 +3192,7 @@
             try {
                 mKeyguardStateCallbacks.get(i).onTrustedChanged(trusted);
             } catch (RemoteException e) {
-                mLogger.logFailedToCallNotifyTrustedChangedLocked(e);
+                Slog.w(TAG, "Failed to call notifyTrustedChangedLocked", e);
                 if (e instanceof DeadObjectException) {
                     mKeyguardStateCallbacks.remove(i);
                 }
@@ -3103,7 +3215,7 @@
                 callback.onTrustedChanged(mUpdateMonitor.getUserHasTrust(
                         KeyguardUpdateMonitor.getCurrentUser()));
             } catch (RemoteException e) {
-                mLogger.logFailedToCallIKeyguardStateCallback(e);
+                Slog.w(TAG, "Failed to call to IKeyguardStateCallback", e);
             }
         }
     }
@@ -3180,7 +3292,7 @@
             // internal state to reflect that immediately, vs. waiting for the launch animator to
             // begin. Otherwise, calls to setShowingLocked, etc. will not know that we're about to
             // be occluded and might re-show the keyguard.
-            mLogger.logOccludeAnimatorOnAnimationStart();
+            Log.d(TAG, "OccludeAnimator#onAnimationStart. Set occluded = true.");
             setOccluded(true /* isOccluded */, false /* animate */);
         }
 
@@ -3188,7 +3300,8 @@
         public void onAnimationCancelled(boolean isKeyguardOccluded) throws RemoteException {
             super.onAnimationCancelled(isKeyguardOccluded);
 
-            mLogger.logOccludeAnimationCancelledByWm(isKeyguardOccluded);
+            Log.d(TAG, "Occlude animation cancelled by WM. "
+                    + "Setting occluded state to: " + isKeyguardOccluded);
             setOccluded(isKeyguardOccluded /* occluded */, false /* animate */);
 
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index fdea62d..56f1ac4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -30,7 +30,6 @@
 import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
 import com.android.keyguard.dagger.KeyguardStatusViewComponent;
 import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
-import com.android.keyguard.logging.KeyguardViewMediatorLogger;
 import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -106,8 +105,7 @@
             InteractionJankMonitor interactionJankMonitor,
             DreamOverlayStateController dreamOverlayStateController,
             Lazy<NotificationShadeWindowController> notificationShadeWindowController,
-            Lazy<ActivityLaunchAnimator> activityLaunchAnimator,
-            KeyguardViewMediatorLogger logger) {
+            Lazy<ActivityLaunchAnimator> activityLaunchAnimator) {
         return new KeyguardViewMediator(
                 context,
                 falsingCollector,
@@ -134,8 +132,7 @@
                 interactionJankMonitor,
                 dreamOverlayStateController,
                 notificationShadeWindowController,
-                activityLaunchAnimator,
-                logger);
+                activityLaunchAnimator);
     }
 
     /** */
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/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index 77ad806..6124e10 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -158,13 +158,8 @@
      * add more detail to every log may do more to improve overall logging than adding more logs
      * with this method.
      */
-    fun log(
-            tag: String,
-            level: LogLevel,
-            @CompileTimeConstant message: String,
-            exception: Throwable? = null
-    ) =
-            log(tag, level, {str1 = message}, { str1!! }, exception)
+    fun log(tag: String, level: LogLevel, @CompileTimeConstant message: String) =
+            log(tag, level, {str1 = message}, { str1!! })
 
     /**
      * You should call [log] instead of this method.
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ChargingLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ChargingLog.java
deleted file mode 100644
index 3cfc22c..0000000
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/ChargingLog.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.log.dagger;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.android.systemui.log.LogBuffer;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-/**
- * A {@link LogBuffer} for {@link com.android.systemui.charging}
- */
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface ChargingLog {
-}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt
index 684839f..323ee219 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardUpdateMonitorLog.kt
@@ -1,7 +1,4 @@
 package com.android.systemui.log.dagger
 
-import javax.inject.Qualifier
-
 /** A [com.android.systemui.log.LogBuffer] for KeyguardUpdateMonitor. */
-@Qualifier
 annotation class KeyguardUpdateMonitorLog
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 1562720..c2a8764 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -305,25 +305,4 @@
     public static LogBuffer provideKeyguardUpdateMonitorLogBuffer(LogBufferFactory factory) {
         return factory.create("KeyguardUpdateMonitorLog", 200);
     }
-
-    /**
-     * Provides a {@link LogBuffer} for use by
-     * {@link com.android.systemui.keyguard.KeyguardViewMediator}.
-     */
-    @Provides
-    @SysUISingleton
-    @KeyguardViewMediatorLog
-    public static LogBuffer provideKeyguardViewMediatorLogBuffer(LogBufferFactory factory) {
-        return factory.create("KeyguardViewMediatorLog", 100);
-    }
-
-    /**
-     * Provides a {@link LogBuffer} for use by {@link com.android.systemui.charging}.
-     */
-    @Provides
-    @SysUISingleton
-    @ChargingLog
-    public static LogBuffer provideChargingLogBuffer(LogBufferFactory factory) {
-        return factory.create("ChargingLog", 20);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
deleted file mode 100644
index 0b15f4f..0000000
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightClockController.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.lowlightclock;
-
-import android.view.ViewGroup;
-
-/**
- * A controller responsible for attaching and showing an optional low-light clock while dozing.
- */
-public interface LowLightClockController {
-    /**
-     * Returns {@code true} if the low-light clock is enabled.
-     */
-    boolean isLowLightClockEnabled();
-
-    /**
-     * Attach the low light-clock to the given parent {@link ViewGroup}.
-     * @param parent The parent {@link ViewGroup} to which the low-light clock view should be
-     *               attached.
-     */
-    void attachLowLightClockView(ViewGroup parent);
-
-    /**
-     * Show or hide the low-light clock.
-     * @param show Whether to show the low-light clock.
-     * @return {@code true} if the low-light clock was shown.
-     */
-    boolean showLowLightClock(boolean show);
-
-    /**
-     * An opportunity to perform burn-in prevention.
-     */
-    void dozeTimeTick();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e9caaaf..cc77ed1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -148,6 +148,32 @@
                 }
             }
         }
+
+    companion object {
+        private const val SQUISHINESS_SCALE_START = 0.5
+        private const val SQUISHINESS_SCALE_FACTOR = 0.5
+        private fun getSquishinessScale(squishinessFraction: Float): Double {
+            return SQUISHINESS_SCALE_START + SQUISHINESS_SCALE_FACTOR * squishinessFraction
+        }
+    }
+
+    var squishinessFraction: Float = 1f
+        set(value) {
+            if (field == value) {
+                return
+            }
+            field = value
+
+            val scale = getSquishinessScale(field)
+            for (mediaPlayer in MediaPlayerData.players()) {
+                mediaPlayer.mediaViewHolder?.let {
+                    it.player.bottom = it.player.top + (scale * it.player.measuredHeight).toInt()
+                } ?: mediaPlayer.recommendationViewHolder?.let {
+                    it.recommendations.bottom = it.recommendations.top +
+                            (scale * it.recommendations.measuredHeight).toInt()
+                }
+            }
+        }
     private val configListener = object : ConfigurationController.ConfigurationListener {
         override fun onDensityOrFontScaleChanged() {
             // System font changes should only happen when UMO is offscreen or a flicker may occur
@@ -432,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(
@@ -446,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
@@ -1009,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) }
     }
@@ -1076,4 +1122,4 @@
     }
 
     fun isSsReactivated(key: String): Boolean = mediaData.get(key)?.isSsReactivated ?: false
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 012d766..b02393b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -488,8 +488,8 @@
         TextView deviceName = mMediaViewHolder.getSeamlessText();
         final MediaDeviceData device = data.getDevice();
 
-        final boolean enabled;
-        final boolean seamlessDisabled;
+        final boolean isTapEnabled;
+        final boolean useDisabledAlpha;
         final int iconResource;
         CharSequence deviceString;
         if (showBroadcastButton) {
@@ -499,21 +499,25 @@
                     && TextUtils.equals(device.getName(),
                     MediaDataUtils.getAppLabel(mContext, mPackageName, mContext.getString(
                             R.string.bt_le_audio_broadcast_dialog_unknown_name)));
-            seamlessDisabled = !mIsCurrentBroadcastedApp;
+            useDisabledAlpha = !mIsCurrentBroadcastedApp;
             // Always be enabled if the broadcast button is shown
-            enabled = true;
+            isTapEnabled = true;
+
+            // Defaults for broadcasting state
             deviceString = mContext.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name);
             iconResource = R.drawable.settings_input_antenna;
         } else {
             // Disable clicking on output switcher for invalid devices and resumption controls
-            seamlessDisabled = (device != null && !device.getEnabled()) || data.getResumption();
-            enabled = !seamlessDisabled;
+            useDisabledAlpha = (device != null && !device.getEnabled()) || data.getResumption();
+            isTapEnabled = !useDisabledAlpha;
+
+            // Defaults for non-broadcasting state
             deviceString = mContext.getString(R.string.media_seamless_other_device);
             iconResource = R.drawable.ic_media_home_devices;
         }
 
-        mMediaViewHolder.getSeamlessButton().setAlpha(seamlessDisabled ? DISABLED_ALPHA : 1.0f);
-        seamlessView.setEnabled(enabled);
+        mMediaViewHolder.getSeamlessButton().setAlpha(useDisabledAlpha ? DISABLED_ALPHA : 1.0f);
+        seamlessView.setEnabled(isTapEnabled);
 
         if (device != null) {
             Drawable icon = device.getIcon();
@@ -524,7 +528,9 @@
             } else {
                 iconView.setImageDrawable(icon);
             }
-            deviceString = device.getName();
+            if (device.getName() != null) {
+                deviceString = device.getName();
+            }
         } else {
             // Set to default icon
             iconView.setImageResource(iconResource);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 7b497ad..c48271e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -518,9 +518,20 @@
             }
             val actions = createActionsFromState(it.packageName,
                     mediaControllerFactory.create(it.token), UserHandle(it.userId))
-            val data = it.copy(
-                    semanticActions = actions,
-                    isPlaying = isPlayingState(state.state))
+
+            // Control buttons
+            // If flag is enabled and controller has a PlaybackState,
+            // create actions from session info
+            // otherwise, no need to update semantic actions.
+            val data = if (actions != null) {
+                it.copy(
+                        semanticActions = actions,
+                        isPlaying = isPlayingState(state.state))
+            } else {
+                it.copy(
+                        isPlaying = isPlayingState(state.state)
+                )
+            }
             if (DEBUG) Log.d(TAG, "State updated outside of notification")
             onMediaDataLoaded(key, key, data)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 2518659..b3a4ddf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -348,7 +348,11 @@
 
                 // If we have a controller but get a null route, then don't trust the device
                 val enabled = device != null && (controller == null || route != null)
-                val name = route?.name?.toString() ?: device?.name
+                val name = if (controller == null || route != null) {
+                    route?.name?.toString() ?: device?.name
+                } else {
+                    null
+                }
                 current = MediaDeviceData(enabled, device?.iconWithoutBackground, name,
                         id = device?.id, showBroadcastButton = false)
             }
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/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index 53abd99..0f1ee31 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -23,35 +23,47 @@
 import android.os.Bundle
 import android.os.IBinder
 import android.os.ResultReceiver
-import android.view.View
+import android.os.UserHandle
+import android.widget.ImageView
 import com.android.internal.app.ChooserActivity
+import com.android.internal.app.ResolverListController
 import com.android.internal.app.chooser.NotSelectableTargetInfo
 import com.android.internal.app.chooser.TargetInfo
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.util.AsyncActivityLauncher
-import com.android.systemui.R;
-import javax.inject.Inject
+import com.android.systemui.R
+import com.android.internal.R as AndroidR
 
-class MediaProjectionAppSelectorActivity @Inject constructor(
-    private val activityLauncher: AsyncActivityLauncher
+class MediaProjectionAppSelectorActivity constructor(
+    private val activityLauncher: AsyncActivityLauncher,
+    /** This is used to override the dependency in a screenshot test */
+    @VisibleForTesting
+    private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)? = null
 ) : ChooserActivity() {
 
+    override fun getLayoutResource() =
+        R.layout.media_projection_app_selector
+
     public override fun onCreate(bundle: Bundle?) {
         val queryIntent = Intent(Intent.ACTION_MAIN)
             .addCategory(Intent.CATEGORY_LAUNCHER)
         intent.putExtra(Intent.EXTRA_INTENT, queryIntent)
 
-        // TODO(b/235465652) Use resource lexeme
-        intent.putExtra(Intent.EXTRA_TITLE, "Record or cast an app")
+        // TODO(b/240939253): update copies
+        val title = getString(R.string.media_projection_dialog_service_title)
+        intent.putExtra(Intent.EXTRA_TITLE, title)
 
         super.onCreate(bundle)
 
-        // TODO(b/235465652) we should update VisD of the title and add an icon
-        findViewById<View>(R.id.title)?.visibility = View.VISIBLE
+        requireViewById<ImageView>(AndroidR.id.icon).setImageResource(R.drawable.ic_present_to_all)
     }
 
     override fun appliedThemeResId(): Int =
         R.style.Theme_SystemUI_MediaProjectionAppSelector
 
+    override fun createListController(userHandle: UserHandle): ResolverListController =
+        listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle)
+
     override fun startSelected(which: Int, always: Boolean, filtered: Boolean) {
         val currentListAdapter = mChooserMultiProfilePagerAdapter.activeListAdapter
         val targetInfo = currentListAdapter.targetInfoForPosition(which, filtered) ?: return
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/dagger/MediaProjectionModule.kt b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
index e33a1b9..9696998 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
@@ -18,8 +18,10 @@
 
 import android.app.Activity
 import com.android.systemui.media.MediaProjectionAppSelectorActivity
+import com.android.systemui.util.AsyncActivityLauncher
 import dagger.Binds
 import dagger.Module
+import dagger.Provides
 import dagger.multibindings.ClassKey
 import dagger.multibindings.IntoMap
 
@@ -29,7 +31,17 @@
     @Binds
     @IntoMap
     @ClassKey(MediaProjectionAppSelectorActivity::class)
-    abstract fun provideMediaProjectionAppSelectorActivity(
+    abstract fun bindMediaProjectionAppSelectorActivity(
         activity: MediaProjectionAppSelectorActivity): Activity
 
+    companion object {
+        @Provides
+        fun provideMediaProjectionAppSelectorActivity(
+            activityLauncher: AsyncActivityLauncher
+        ): MediaProjectionAppSelectorActivity {
+            return MediaProjectionAppSelectorActivity(
+                activityLauncher
+            )
+        }
+    }
 }
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 08cf57c..b39770d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -356,15 +356,6 @@
             mHeaderSubtitle.setText(subTitle);
             mHeaderTitle.setGravity(Gravity.NO_GRAVITY);
         }
-        if (!mAdapter.isDragging()) {
-            int currentActivePosition = mAdapter.getCurrentActivePosition();
-            if (!colorSetUpdated && !deviceSetChanged && currentActivePosition >= 0
-                    && currentActivePosition < mAdapter.getItemCount()) {
-                mAdapter.notifyItemChanged(currentActivePosition);
-            } else {
-                mAdapter.notifyDataSetChanged();
-            }
-        }
         // Show when remote media session is available or
         //      when the device supports BT LE audio + media is playing
         mStopButton.setVisibility(getStopButtonVisibility());
@@ -374,6 +365,18 @@
 
         mBroadcastIcon.setVisibility(getBroadcastIconVisibility());
         mBroadcastIcon.setOnClickListener(v -> onBroadcastIconClick());
+        if (!mAdapter.isDragging()) {
+            int currentActivePosition = mAdapter.getCurrentActivePosition();
+            if (!colorSetUpdated && !deviceSetChanged && currentActivePosition >= 0
+                    && currentActivePosition < mAdapter.getItemCount()) {
+                mAdapter.notifyItemChanged(currentActivePosition);
+            } else {
+                mAdapter.notifyDataSetChanged();
+            }
+        } else {
+            mMediaOutputController.setRefreshing(false);
+            mMediaOutputController.refreshDataSetIfNeeded();
+        }
     }
 
     private void updateButtonBackgroundColorFilter() {
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 c544871..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,12 +19,14 @@
 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;
 
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.complication.DreamMediaEntryComplication;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaData;
 import com.android.systemui.media.MediaDataManager;
@@ -37,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
@@ -45,16 +50,22 @@
 
         @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;
             }
 
             mAdded = false;
-            mDreamOverlayStateController.removeComplication(mComplication);
+            mDreamOverlayStateController.removeComplication(mMediaEntryComplication);
         }
 
         @Override
@@ -70,33 +81,46 @@
                 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;
             }
 
             mAdded = true;
-            mDreamOverlayStateController.addComplication(mComplication);
+            mDreamOverlayStateController.addComplication(mMediaEntryComplication);
         }
     };
 
     private final MediaDataManager mMediaDataManager;
     private final DreamOverlayStateController mDreamOverlayStateController;
-    private final MediaDreamComplication mComplication;
+    private final DreamMediaEntryComplication mMediaEntryComplication;
     private final FeatureFlags mFeatureFlags;
 
     @Inject
     public MediaDreamSentinel(Context context, MediaDataManager mediaDataManager,
             DreamOverlayStateController dreamOverlayStateController,
-            MediaDreamComplication complication,
+            DreamMediaEntryComplication mediaEntryComplication,
             FeatureFlags featureFlags) {
         super(context);
         mMediaDataManager = mediaDataManager;
         mDreamOverlayStateController = dreamOverlayStateController;
-        mComplication = complication;
+        mMediaEntryComplication = mediaEntryComplication;
         mFeatureFlags = featureFlags;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java
index 3408d97..052608f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/dagger/MediaComplicationComponent.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media.dream.dagger;
 
+import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_COMPLICATION_WEIGHT;
+
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 import android.content.Context;
@@ -93,7 +95,7 @@
                     ComplicationLayoutParams.POSITION_TOP
                             | ComplicationLayoutParams.POSITION_START,
                     ComplicationLayoutParams.DIRECTION_DOWN,
-                    0,
+                    DREAM_MEDIA_COMPLICATION_WEIGHT,
                     true);
         }
     }
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 00a22f2..5d6d683 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
@@ -30,20 +30,18 @@
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
-import androidx.core.graphics.ColorUtils
 import com.android.settingslib.Utils
 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.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
 
 /**
@@ -57,18 +55,16 @@
         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>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
@@ -120,18 +116,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.
@@ -139,19 +135,19 @@
         )
     }
 
-    override fun updateChipView(newChipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
-        super.updateChipView(newChipInfo, currentChipView)
+    override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
+        super.updateView(newInfo, currentView)
         val iconName = setIcon(
-                currentChipView,
-                newChipInfo.routeInfo.clientPackageName,
-                newChipInfo.appIconDrawableOverride,
-                newChipInfo.appNameOverride
+                currentView,
+                newInfo.routeInfo.clientPackageName,
+                newInfo.appIconDrawableOverride,
+                newInfo.appNameOverride
         )
-        currentChipView.contentDescription = iconName
+        currentView.contentDescription = iconName
     }
 
-    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)
@@ -161,8 +157,8 @@
                 .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? =
@@ -209,8 +205,7 @@
         // Center the ripple on the bottom of the screen in the middle.
         rippleView.setCenter(width * 0.5f, height.toFloat())
         val color = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
-        val colorWithAlpha = ColorUtils.setAlphaComponent(color, 70)
-        rippleView.setColor(colorWithAlpha)
+        rippleView.setColor(color, 70)
     }
 }
 
@@ -218,7 +213,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..bde588c 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
@@ -120,7 +120,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
                     )
@@ -155,7 +155,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
                     )
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..0c1ebd7 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,13 @@
 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.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,17 +52,15 @@
         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>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
@@ -106,53 +103,52 @@
         uiEventLogger.logSenderStateChange(chipState)
 
         if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
-            removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
+            removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
         } 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 iconName = setIcon(currentView, newInfo.routeInfo.clientPackageName)
 
         // 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 =
+        currentView.requireViewById<View>(R.id.loading).visibility =
             chipState.isMidTransfer.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 =
+        currentView.requireViewById<View>(R.id.failure_icon).visibility =
             chipState.isTransferFailure.visibleIfTrue()
 
         // For accessibility
-        currentChipView.requireViewById<ViewGroup>(
+        currentView.requireViewById<ViewGroup>(
                 R.id.media_ttt_sender_chip_inner
         ).contentDescription = "$iconName $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 +161,14 @@
         )
     }
 
-    override fun removeChip(removalReason: String) {
+    override fun removeView(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) {
+        if (info?.state?.isMidTransfer == true &&
+                removalReason != TemporaryDisplayRemovalReason.REASON_TIMEOUT) {
             return
         }
-        super.removeChip(removalReason)
+        super.removeView(removalReason)
     }
 
     private fun Boolean.visibleIfTrue(): Int {
@@ -188,7 +184,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/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/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
similarity index 73%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
index 88e227b..491da65 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/data/repository/PowerRepositoryModule.kt
@@ -12,12 +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.log.dagger
+package com.android.systemui.power.data.repository
 
-import javax.inject.Qualifier
+import dagger.Binds
+import dagger.Module
 
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+@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..920f463 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()} }
@@ -125,14 +131,11 @@
     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;
@@ -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) {
@@ -339,8 +325,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,7 +407,7 @@
                     mAnimatedQsViews.add(tileView);
                     mAllViews.add(quickTileView);
                     mAllViews.add(quickTileView.getSecondaryLabel());
-                } else if (mFullRows && isIconInAnimatedRow(count)) {
+                } else if (isIconInAnimatedRow(count)) {
 
                     firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
 
@@ -457,44 +442,42 @@
             }
         }
 
-        if (mAllowFancy) {
-            animateBrightnessSlider(firstPageBuilder);
+        animateBrightnessSlider(firstPageBuilder);
 
-            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 +551,7 @@
 
             if (animator == null) {
                 animator = new HeightExpansionAnimator(
-                                this, mLastQQSTileHeight, tileView.getMeasuredHeight());
+                        this, mLastQQSTileHeight, tileView.getMeasuredHeight());
                 animator.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
             }
             animator.addView(tileView);
@@ -639,7 +622,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 +655,6 @@
             }
         }
         mLastPosition = position;
-        if (!mAllowFancy) return;
         if (mOnFirstPage) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
@@ -806,30 +788,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/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 8fe280f..072c32f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -18,7 +18,7 @@
 
 import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
 import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
-import static com.android.systemui.statusbar.DisableFlagsLogger.DisableState;
+import static com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -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,
@@ -571,15 +579,17 @@
     }
 
     @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 +608,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);
@@ -684,10 +698,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/QSFragmentDisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
index 8544f61..e5d86cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragmentDisableFlagsLogger.kt
@@ -3,7 +3,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogLevel
 import com.android.systemui.log.dagger.QSFragmentDisableLog
-import com.android.systemui.statusbar.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
 import javax.inject.Inject
 
 /** A helper class for logging disable flag changes made in [QSFragment]. */
@@ -44,4 +44,4 @@
     }
 }
 
-private const val TAG = "QSFragmentDisableFlagsLog"
\ No newline at end of file
+private const val TAG = "QSFragmentDisableFlagsLog"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index 918c6be..59b871c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -27,8 +27,8 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.media.MediaHostState;
@@ -61,8 +61,6 @@
     private final BrightnessMirrorHandler mBrightnessMirrorHandler;
     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
-    private boolean mGridContentVisible = true;
-
     private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
             new QSPanel.OnConfigurationChangedListener() {
         @Override
@@ -90,13 +88,14 @@
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QS_PANEL) MediaHost mediaHost,
             QSTileRevealController.Factory qsTileRevealControllerFactory,
-            DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
+            DumpManager dumpManager, MediaCarouselController mediaCarouselController,
+            MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
             QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
             BrightnessSliderController.Factory brightnessSliderFactory,
             FalsingManager falsingManager,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
-                metricsLogger, uiEventLogger, qsLogger, dumpManager);
+                metricsLogger, uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
         mTunerService = tunerService;
         mQsCustomizerController = qsCustomizerController;
         mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
@@ -204,16 +203,6 @@
         });
     }
 
-    /** */
-    public void setGridContentVisibility(boolean visible) {
-        int newVis = visible ? View.VISIBLE : View.INVISIBLE;
-        setVisibility(newVis);
-        if (mGridContentVisible != visible) {
-            mMetricsLogger.visibility(MetricsEvent.QS_PANEL, newVis);
-        }
-        mGridContentVisible = visible;
-    }
-
     public boolean isLayoutRtl() {
         return mView.isLayoutRtl();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6d5f844..57bea67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -31,6 +31,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dumpable;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
@@ -68,6 +69,7 @@
     private final UiEventLogger mUiEventLogger;
     private final QSLogger mQSLogger;
     private final DumpManager mDumpManager;
+    private final MediaCarouselController mMediaCarouselController;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
     protected boolean mShouldUseSplitNotificationShade;
 
@@ -122,7 +124,8 @@
             MetricsLogger metricsLogger,
             UiEventLogger uiEventLogger,
             QSLogger qsLogger,
-            DumpManager dumpManager
+            DumpManager dumpManager,
+            MediaCarouselController mediaCarouselController
     ) {
         super(view);
         mHost = host;
@@ -135,6 +138,7 @@
         mDumpManager = dumpManager;
         mShouldUseSplitNotificationShade =
                 LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+        mMediaCarouselController = mediaCarouselController;
     }
 
     @Override
@@ -152,6 +156,7 @@
 
     public void setSquishinessFraction(float squishinessFraction) {
         mView.setSquishinessFraction(squishinessFraction);
+        mMediaCarouselController.setSquishinessFraction(squishinessFraction);
     }
 
     @Override
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/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
index 3f93108..5da4809 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java
@@ -17,7 +17,14 @@
 
 import javax.inject.Inject;
 
-/** */
+/**
+ * Plays a animation to reveal newly added QS tiles.
+ *
+ * The aniumation is played when the user fully opens Quick Settings, and is only shown for
+ * <li> tiles added automatically (not through user customization)
+ * <li> tiles not have been revealed before (memoized via {@code QS_TILE_SPECS_REVEALED}
+ * preference)
+ */
 public class QSTileRevealController {
     private static final long QS_REVEAL_TILES_DELAY = 500L;
 
@@ -39,6 +46,7 @@
             });
         }
     };
+
     QSTileRevealController(Context context, QSPanelController qsPanelController,
             PagedTileLayout pagedTileLayout, QSCustomizerController qsCustomizerController) {
         mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 112b1e8..46724ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -54,7 +54,9 @@
 
     @Override
     public TileLayout getOrCreateTileLayout() {
-        return new QQSSideLabelTileLayout(mContext);
+        QQSSideLabelTileLayout layout = new QQSSideLabelTileLayout(mContext);
+        layout.setId(R.id.qqs_tile_layout);
+        return layout;
     }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index be44202..c86e6e8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -26,6 +26,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
@@ -63,10 +64,10 @@
             @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
                     Provider<Boolean> usingCollapsedLandscapeMediaProvider,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-            DumpManager dumpManager
+            DumpManager dumpManager, MediaCarouselController mediaCarouselController
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
-                uiEventLogger, qsLogger, dumpManager);
+                uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
         mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index 2a6cf66..b585961 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -128,6 +128,8 @@
         mPrivacyIconsController.setChipVisibilityListener(this);
         mIconContainer.addIgnoredSlot(
                 getResources().getString(com.android.internal.R.string.status_bar_managed_profile));
+        mIconContainer.addIgnoredSlot(
+                getResources().getString(com.android.internal.R.string.status_bar_alarm_clock));
         mIconContainer.setShouldRestrictIcons(false);
         mStatusBarIconController.addIconGroup(mIconManager);
 
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 be6982a..5842665 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -165,7 +165,7 @@
             iv.clearColorFilter();
         }
         if (state.state != mState) {
-            int color = getColor(state.state);
+            int color = getColor(state);
             mState = state.state;
             if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
                 animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
@@ -183,7 +183,7 @@
         }
     }
 
-    protected int getColor(int state) {
+    protected int getColor(QSTile.State state) {
         return getIconColorForState(getContext(), state);
     }
 
@@ -239,19 +239,18 @@
     /**
      * Color to tint the tile icon based on state
      */
-    public static int getIconColorForState(Context context, int state) {
-        switch (state) {
-            case Tile.STATE_UNAVAILABLE:
-                return Utils.applyAlpha(QSTileViewImpl.UNAVAILABLE_ALPHA,
-                        Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary));
-            case Tile.STATE_INACTIVE:
-                return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
-            case Tile.STATE_ACTIVE:
-                return Utils.getColorAttrDefaultColor(context,
-                        com.android.internal.R.attr.textColorOnAccent);
-            default:
-                Log.e("QSIconView", "Invalid state " + state);
-                return 0;
+    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));
+        } else if (state.state == Tile.STATE_INACTIVE) {
+            return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
+        } else if (state.state == Tile.STATE_ACTIVE) {
+            return Utils.getColorAttrDefaultColor(context,
+                    com.android.internal.R.attr.textColorOnAccent);
+        } else {
+            Log.e("QSIconView", "Invalid state " + state);
+            return 0;
         }
     }
 
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 2731d64..163ee2a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -35,6 +35,7 @@
 import android.view.ViewGroup
 import android.view.accessibility.AccessibilityEvent
 import android.view.accessibility.AccessibilityNodeInfo
+import android.widget.Button
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.Switch
@@ -144,6 +145,7 @@
         superSetVisibility = { super.setVisibility(it) },
         superSetTransitionVisibility = { super.setTransitionVisibility(it) },
     )
+    private var lastDisabledByPolicy = false
 
     private val locInScreen = IntArray(2)
 
@@ -376,8 +378,22 @@
         super.onInitializeAccessibilityNodeInfo(info)
         // Clear selected state so it is not announce by talkback.
         info.isSelected = false
+        if (lastDisabledByPolicy) {
+            info.addAction(
+                    AccessibilityNodeInfo.AccessibilityAction(
+                            AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
+                            resources.getString(
+                                R.string.accessibility_tile_disabled_by_policy_action_description
+                            )
+                    )
+            )
+        }
         if (!TextUtils.isEmpty(accessibilityClass)) {
-            info.className = accessibilityClass
+            info.className = if (lastDisabledByPolicy) {
+                Button::class.java.name
+            } else {
+                accessibilityClass
+            }
             if (Switch::class.java.name == accessibilityClass) {
                 val label = resources.getString(
                         if (tileState) R.string.switch_bar_on else R.string.switch_bar_off)
@@ -430,6 +446,10 @@
                 state.secondaryLabel = stateText
             }
         }
+        if (state.disabledByPolicy && state.state != Tile.STATE_UNAVAILABLE) {
+            stateDescription.append(", ")
+            stateDescription.append(getUnavailableText(state.spec))
+        }
         if (!TextUtils.isEmpty(state.stateDescription)) {
             stateDescription.append(", ")
             stateDescription.append(state.stateDescription)
@@ -470,38 +490,38 @@
         }
 
         // Colors
-        if (state.state != lastState) {
+        if (state.state != lastState || state.disabledByPolicy || lastDisabledByPolicy) {
             singleAnimator.cancel()
             if (allowAnimations) {
                 singleAnimator.setValues(
                         colorValuesHolder(
                                 BACKGROUND_NAME,
                                 paintColor,
-                                getBackgroundColorForState(state.state)
+                                getBackgroundColorForState(state.state, state.disabledByPolicy)
                         ),
                         colorValuesHolder(
                                 LABEL_NAME,
                                 label.currentTextColor,
-                                getLabelColorForState(state.state)
+                                getLabelColorForState(state.state, state.disabledByPolicy)
                         ),
                         colorValuesHolder(
                                 SECONDARY_LABEL_NAME,
                                 secondaryLabel.currentTextColor,
-                                getSecondaryLabelColorForState(state.state)
+                                getSecondaryLabelColorForState(state.state, state.disabledByPolicy)
                         ),
                         colorValuesHolder(
                                 CHEVRON_NAME,
                                 chevronView.imageTintList?.defaultColor ?: 0,
-                                getChevronColorForState(state.state)
+                                getChevronColorForState(state.state, state.disabledByPolicy)
                         )
                     )
                 singleAnimator.start()
             } else {
                 setAllColors(
-                    getBackgroundColorForState(state.state),
-                    getLabelColorForState(state.state),
-                    getSecondaryLabelColorForState(state.state),
-                    getChevronColorForState(state.state)
+                    getBackgroundColorForState(state.state, state.disabledByPolicy),
+                    getLabelColorForState(state.state, state.disabledByPolicy),
+                    getSecondaryLabelColorForState(state.state, state.disabledByPolicy),
+                    getChevronColorForState(state.state, state.disabledByPolicy)
                 )
             }
         }
@@ -512,6 +532,7 @@
         label.isEnabled = !state.disabledByPolicy
 
         lastState = state.state
+        lastDisabledByPolicy = state.disabledByPolicy
     }
 
     private fun setAllColors(
@@ -559,13 +580,14 @@
         }
     }
 
-    private fun getStateText(state: QSTile.State): String {
-        if (state.disabledByPolicy) {
-            return context.getString(R.string.tile_disabled)
-        }
+    private fun getUnavailableText(spec: String?): String {
+        val arrayResId = SubtitleArrayMapping.getSubtitleId(spec)
+        return resources.getStringArray(arrayResId)[Tile.STATE_UNAVAILABLE]
+    }
 
+    private fun getStateText(state: QSTile.State): String {
         return if (state.state == Tile.STATE_UNAVAILABLE || state is BooleanState) {
-            var arrayResId = SubtitleArrayMapping.getSubtitleId(state.spec)
+            val arrayResId = SubtitleArrayMapping.getSubtitleId(state.spec)
             val array = resources.getStringArray(arrayResId)
             array[state.state]
         } else {
@@ -587,11 +609,11 @@
         return locInScreen.get(1) >= -height
     }
 
-    private fun getBackgroundColorForState(state: Int): Int {
-        return when (state) {
-            Tile.STATE_ACTIVE -> colorActive
-            Tile.STATE_INACTIVE -> colorInactive
-            Tile.STATE_UNAVAILABLE -> colorUnavailable
+    private fun getBackgroundColorForState(state: Int, disabledByPolicy: Boolean = false): Int {
+        return when {
+            state == Tile.STATE_UNAVAILABLE || disabledByPolicy -> colorUnavailable
+            state == Tile.STATE_ACTIVE -> colorActive
+            state == Tile.STATE_INACTIVE -> colorInactive
             else -> {
                 Log.e(TAG, "Invalid state $state")
                 0
@@ -599,11 +621,11 @@
         }
     }
 
-    private fun getLabelColorForState(state: Int): Int {
-        return when (state) {
-            Tile.STATE_ACTIVE -> colorLabelActive
-            Tile.STATE_INACTIVE -> colorLabelInactive
-            Tile.STATE_UNAVAILABLE -> colorLabelUnavailable
+    private fun getLabelColorForState(state: Int, disabledByPolicy: Boolean = false): Int {
+        return when {
+            state == Tile.STATE_UNAVAILABLE || disabledByPolicy -> colorLabelUnavailable
+            state == Tile.STATE_ACTIVE -> colorLabelActive
+            state == Tile.STATE_INACTIVE -> colorLabelInactive
             else -> {
                 Log.e(TAG, "Invalid state $state")
                 0
@@ -611,11 +633,11 @@
         }
     }
 
-    private fun getSecondaryLabelColorForState(state: Int): Int {
-        return when (state) {
-            Tile.STATE_ACTIVE -> colorSecondaryLabelActive
-            Tile.STATE_INACTIVE -> colorSecondaryLabelInactive
-            Tile.STATE_UNAVAILABLE -> colorSecondaryLabelUnavailable
+    private fun getSecondaryLabelColorForState(state: Int, disabledByPolicy: Boolean = false): Int {
+        return when {
+            state == Tile.STATE_UNAVAILABLE || disabledByPolicy -> colorSecondaryLabelUnavailable
+            state == Tile.STATE_ACTIVE -> colorSecondaryLabelActive
+            state == Tile.STATE_INACTIVE -> colorSecondaryLabelInactive
             else -> {
                 Log.e(TAG, "Invalid state $state")
                 0
@@ -623,7 +645,16 @@
         }
     }
 
-    private fun getChevronColorForState(state: Int): Int = getSecondaryLabelColorForState(state)
+    private fun getChevronColorForState(state: Int, disabledByPolicy: Boolean = false): Int =
+            getSecondaryLabelColorForState(state, disabledByPolicy)
+
+    @VisibleForTesting
+    internal fun getCurrentColors(): List<Int> = listOf(
+            paintColor,
+            label.currentTextColor,
+            secondaryLabel.currentTextColor,
+            chevronView.imageTintList?.defaultColor ?: 0
+    )
 }
 
 @VisibleForTesting
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/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index ce6aaae..0ec4eef 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -43,6 +43,7 @@
 import com.android.systemui.qs.user.UserSwitchDialogController;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.user.data.source.UserRecord;
 
 import javax.inject.Inject;
 
@@ -95,7 +96,7 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            UserSwitcherController.UserRecord item = getItem(position);
+            UserRecord item = getItem(position);
             return createUserDetailItemView(convertView, parent, item);
         }
 
@@ -113,7 +114,7 @@
         }
 
         public UserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent,
-                UserSwitcherController.UserRecord item) {
+                UserRecord item) {
             UserDetailItemView v = UserDetailItemView.convertOrInflate(
                     parent.getContext(), convertView, parent);
             if (!item.isCurrent || item.isGuest) {
@@ -134,7 +135,7 @@
                 v.bind(name, drawable, item.info.id);
             }
             v.setActivated(item.isCurrent);
-            v.setDisabledByAdmin(item.isDisabledByAdmin);
+            v.setDisabledByAdmin(mController.isDisabledByAdmin(item));
             v.setEnabled(item.isSwitchToEnabled);
             v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA);
 
@@ -146,7 +147,7 @@
         }
 
         private static Drawable getDrawable(Context context,
-                UserSwitcherController.UserRecord item) {
+                UserRecord item) {
             Drawable icon = getIconDrawable(context, item);
             int iconColorRes;
             if (item.isCurrent) {
@@ -171,22 +172,24 @@
             }
 
             Trace.beginSection("UserDetailView.Adapter#onClick");
-            UserSwitcherController.UserRecord tag =
-                    (UserSwitcherController.UserRecord) view.getTag();
-            if (tag.isDisabledByAdmin) {
+            UserRecord userRecord =
+                    (UserRecord) view.getTag();
+            if (mController.isDisabledByAdmin(userRecord)) {
                 final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
-                        mContext, tag.enforcedAdmin);
+                        mContext, mController.getEnforcedAdmin(userRecord));
                 mController.startActivity(intent);
-            } else if (tag.isSwitchToEnabled) {
+            } else if (userRecord.isSwitchToEnabled) {
                 MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
                 mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_SWITCH);
-                if (!tag.isAddUser && !tag.isRestricted && !tag.isDisabledByAdmin) {
+                if (!userRecord.isAddUser
+                        && !userRecord.isRestricted
+                        && !mController.isDisabledByAdmin(userRecord)) {
                     if (mCurrentUserView != null) {
                         mCurrentUserView.setActivated(false);
                     }
                     view.setActivated(true);
                 }
-                onUserListItemClicked(tag, mDialogShower);
+                onUserListItemClicked(userRecord, mDialogShower);
             }
             Trace.endSection();
         }
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/ripple/RippleView.kt b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
index 60c8f37..1e51ffa 100644
--- a/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/ripple/RippleView.kt
@@ -25,10 +25,12 @@
 import android.graphics.Paint
 import android.util.AttributeSet
 import android.view.View
+import androidx.core.graphics.ColorUtils
 import com.android.systemui.ripple.RippleShader.RippleShape
 
 private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
 private const val RIPPLE_DEFAULT_COLOR: Int = 0xffffffff.toInt()
+const val RIPPLE_DEFAULT_ALPHA: Int = 45
 
 /**
  * A generic expanding ripple effect.
@@ -111,9 +113,12 @@
         rippleInProgress = true
     }
 
-    /** Set the color to be used for the ripple. */
-    fun setColor(color: Int) {
-        rippleShader.color = color
+    /** Set the color to be used for the ripple.
+     *
+     * The alpha value of the color will be applied to the ripple. The alpha range is [0-100].
+     */
+    fun setColor(color: Int, alpha: Int = RIPPLE_DEFAULT_ALPHA) {
+        rippleShader.color = ColorUtils.setAlphaComponent(color, alpha)
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
index a918e5d..309059f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/RequestProcessor.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.screenshot
 
 import android.graphics.Insets
+import android.util.Log
 import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
 import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
 import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
@@ -61,8 +62,9 @@
         ) {
 
             val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
+            Log.d(TAG, "findPrimaryContent: $info")
 
-            result = if (policy.isManagedProfile(info.userId)) {
+            result = if (policy.isManagedProfile(info.user.identifier)) {
                 val image = capture.captureTask(info.taskId)
                     ?: error("Task snapshot returned a null Bitmap!")
 
@@ -70,7 +72,7 @@
                 ScreenshotRequest(
                     TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source,
                     HardwareBitmapBundler.hardwareBitmapToBundle(image),
-                    info.bounds, Insets.NONE, info.taskId, info.userId, info.component
+                    info.bounds, Insets.NONE, info.taskId, info.user.identifier, info.component
                 )
             } else {
                 // Create a new request of the same type which includes the top component
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
index 3580010..f73d204 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicy.kt
@@ -19,6 +19,7 @@
 import android.annotation.UserIdInt
 import android.content.ComponentName
 import android.graphics.Rect
+import android.os.UserHandle
 import android.view.Display
 
 /**
@@ -42,7 +43,7 @@
     data class DisplayContentInfo(
         val component: ComponentName,
         val bounds: Rect,
-        @UserIdInt val userId: Int,
+        val user: UserHandle,
         val taskId: Int,
     )
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
index ba809f6..c2a5060 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
@@ -29,9 +29,11 @@
 import android.graphics.Rect
 import android.os.Process
 import android.os.RemoteException
+import android.os.UserHandle
 import android.os.UserManager
 import android.util.Log
 import android.view.Display.DEFAULT_DISPLAY
+import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.infra.ServiceConnector
 import com.android.systemui.SystemUIService
 import com.android.systemui.dagger.SysUISingleton
@@ -45,21 +47,13 @@
 import kotlinx.coroutines.withContext
 
 @SysUISingleton
-internal class ScreenshotPolicyImpl @Inject constructor(
+internal open class ScreenshotPolicyImpl @Inject constructor(
     context: Context,
     private val userMgr: UserManager,
     private val atmService: IActivityTaskManager,
     @Background val bgDispatcher: CoroutineDispatcher,
 ) : ScreenshotPolicy {
 
-    private val systemUiContent =
-        DisplayContentInfo(
-            ComponentName(context, SystemUIService::class.java),
-            Rect(),
-            ActivityTaskManager.INVALID_TASK_ID,
-            Process.myUserHandle().identifier,
-        )
-
     private val proxyConnector: ServiceConnector<IScreenshotProxy> =
         ServiceConnector.Impl(
             context,
@@ -78,6 +72,9 @@
     }
 
     private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
+        if (DEBUG) {
+            debugLogRootTaskInfo(info)
+        }
         return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
             info.isVisible &&
             info.isRunning &&
@@ -99,58 +96,46 @@
         }
 
         val taskInfoList = getAllRootTaskInfosOnDisplay(displayId)
-        if (DEBUG) {
-            debugLogRootTaskInfos(taskInfoList)
-        }
 
         // If no visible task is located, then report SystemUI as the foreground content
         val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent
-
-        val topActivity: ComponentName = target.topActivity ?: error("should not be null")
-        val topChildTask = target.childTaskIds.size - 1
-        val childTaskId = target.childTaskIds[topChildTask]
-        val childTaskUserId = target.childTaskUserIds[topChildTask]
-        val childTaskBounds = target.childTaskBounds[topChildTask]
-
-        return DisplayContentInfo(topActivity, childTaskBounds, childTaskId, childTaskUserId)
+        return target.toDisplayContentInfo()
     }
 
-    private fun debugLogRootTaskInfos(taskInfoList: List<RootTaskInfo>) {
-        for (info in taskInfoList) {
-            Log.d(
-                TAG,
-                "[root task info] " +
-                    "taskId=${info.taskId} " +
-                    "parentTaskId=${info.parentTaskId} " +
-                    "position=${info.position} " +
-                    "positionInParent=${info.positionInParent} " +
-                    "isVisible=${info.isVisible()} " +
-                    "visible=${info.visible} " +
-                    "isFocused=${info.isFocused} " +
-                    "isSleeping=${info.isSleeping} " +
-                    "isRunning=${info.isRunning} " +
-                    "windowMode=${windowingModeToString(info.windowingMode)} " +
-                    "activityType=${activityTypeToString(info.activityType)} " +
-                    "topActivity=${info.topActivity} " +
-                    "topActivityInfo=${info.topActivityInfo} " +
-                    "numActivities=${info.numActivities} " +
-                    "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
-                    "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
-                    "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
-                    "childTaskNames=${Arrays.toString(info.childTaskNames)}"
-            )
+    private fun debugLogRootTaskInfo(info: RootTaskInfo) {
+        Log.d(TAG, "RootTaskInfo={" +
+                "taskId=${info.taskId} " +
+                "parentTaskId=${info.parentTaskId} " +
+                "position=${info.position} " +
+                "positionInParent=${info.positionInParent} " +
+                "isVisible=${info.isVisible()} " +
+                "visible=${info.visible} " +
+                "isFocused=${info.isFocused} " +
+                "isSleeping=${info.isSleeping} " +
+                "isRunning=${info.isRunning} " +
+                "windowMode=${windowingModeToString(info.windowingMode)} " +
+                "activityType=${activityTypeToString(info.activityType)} " +
+                "topActivity=${info.topActivity} " +
+                "topActivityInfo=${info.topActivityInfo} " +
+                "numActivities=${info.numActivities} " +
+                "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
+                "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
+                "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
+                "childTaskNames=${Arrays.toString(info.childTaskNames)}" +
+                "}"
+        )
 
-            for (j in 0 until info.childTaskIds.size) {
-                Log.d(TAG, "    *** [$j] ******")
-                Log.d(TAG, "        ***  childTaskIds[$j]: ${info.childTaskIds[j]}")
-                Log.d(TAG, "        ***  childTaskUserIds[$j]: ${info.childTaskUserIds[j]}")
-                Log.d(TAG, "        ***  childTaskBounds[$j]: ${info.childTaskBounds[j]}")
-                Log.d(TAG, "        ***  childTaskNames[$j]: ${info.childTaskNames[j]}")
-            }
+        for (j in 0 until info.childTaskIds.size) {
+            Log.d(TAG, "    *** [$j] ******")
+            Log.d(TAG, "        ***  childTaskIds[$j]: ${info.childTaskIds[j]}")
+            Log.d(TAG, "        ***  childTaskUserIds[$j]: ${info.childTaskUserIds[j]}")
+            Log.d(TAG, "        ***  childTaskBounds[$j]: ${info.childTaskBounds[j]}")
+            Log.d(TAG, "        ***  childTaskNames[$j]: ${info.childTaskNames[j]}")
         }
     }
 
-    private suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
+    @VisibleForTesting
+    open suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
         withContext(bgDispatcher) {
             try {
                 atmService.getAllRootTaskInfosOnDisplay(displayId)
@@ -160,7 +145,8 @@
             }
         }
 
-    private suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
+    @VisibleForTesting
+    open suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
         proxyConnector
             .postForResult { it.isNotificationShadeExpanded }
             .whenComplete { expanded, error ->
@@ -171,8 +157,30 @@
             }
     }
 
-    companion object {
-        const val TAG: String = "ScreenshotPolicyImpl"
-        const val DEBUG: Boolean = false
-    }
+    @VisibleForTesting
+    internal val systemUiContent =
+        DisplayContentInfo(
+            ComponentName(context, SystemUIService::class.java),
+            Rect(),
+            Process.myUserHandle(),
+            ActivityTaskManager.INVALID_TASK_ID
+        )
+}
+
+private const val TAG: String = "ScreenshotPolicyImpl"
+private const val DEBUG: Boolean = false
+
+@VisibleForTesting
+internal fun RootTaskInfo.toDisplayContentInfo(): DisplayContentInfo {
+    val topActivity: ComponentName = topActivity ?: error("should not be null")
+    val topChildTask = childTaskIds.size - 1
+    val childTaskId = childTaskIds[topChildTask]
+    val childTaskUserId = childTaskUserIds[topChildTask]
+    val childTaskBounds = childTaskBounds[topChildTask]
+
+    return DisplayContentInfo(
+        topActivity,
+        childTaskBounds,
+        UserHandle.of(childTaskUserId),
+        childTaskId)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 35f32ca..695a80b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -229,6 +229,7 @@
             Log.d(TAG, "handleMessage: Using request processor");
             mProcessor.processAsync(request,
                     (r) -> dispatchToController(r, onSaved, callback));
+            return;
         }
 
         dispatchToController(request, onSaved, callback);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index fab70fc..6b32daf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -270,6 +270,14 @@
         qsCarrierGroupController = qsCarrierGroupControllerBuilder
             .setQSCarrierGroup(qsCarrierGroup)
             .build()
+
+        if (!combinedHeaders) {
+            // In the new header, we display alarm icon but we ignore it when not using the new
+            // headers.
+            iconContainer.addIgnoredSlot(
+                    context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+            )
+        }
     }
 
     override fun onViewAttached() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
index 9818af3..1cdacb9 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelView.java
@@ -17,32 +17,30 @@
 package com.android.systemui.shade;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.TapAgainView;
 
-public class NotificationPanelView extends PanelView {
+/** The shade view. */
+public final class NotificationPanelView extends FrameLayout {
+    static final boolean DEBUG = false;
 
-    private static final boolean DEBUG = false;
-
-    /**
-     * Fling expanding QS.
-     */
-    public static final int FLING_EXPAND = 0;
-
-    public static final String COUNTER_PANEL_OPEN = "panel_open";
-    public static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
+    private final Paint mAlphaPaint = new Paint();
 
     private int mCurrentPanelAlpha;
-    private final Paint mAlphaPaint = new Paint();
     private boolean mDozing;
     private RtlChangeListener mRtlChangeListener;
+    private NotificationPanelViewController.TouchHandler mTouchHandler;
+    private OnConfigurationChangedListener mOnConfigurationChangedListener;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -99,7 +97,36 @@
         return findViewById(R.id.shade_falsing_tap_again);
     }
 
+    /** Sets the touch handler for this view. */
+    public void setOnTouchListener(NotificationPanelViewController.TouchHandler touchHandler) {
+        super.setOnTouchListener(touchHandler);
+        mTouchHandler = touchHandler;
+    }
+
+    void setOnConfigurationChangedListener(OnConfigurationChangedListener listener) {
+        mOnConfigurationChangedListener = listener;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent event) {
+        return mTouchHandler.onInterceptTouchEvent(event);
+    }
+
+    @Override
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        super.dispatchConfigurationChanged(newConfig);
+        mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
+    }
+
+    /** Callback for right-to-left setting changes. */
     interface RtlChangeListener {
+        /** Called when right-to-left setting changes. */
         void onRtlPropertielsChanged(int layoutDirection);
     }
+
+    /** Callback for config changes. */
+    interface OnConfigurationChangedListener {
+        /** Called when configuration changes. */
+        void onConfigurationChanged(Configuration newConfig);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 5f07f9f..156b123 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -17,8 +17,6 @@
 package com.android.systemui.shade;
 
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
 
 import static androidx.constraintlayout.widget.ConstraintSet.END;
 import static androidx.constraintlayout.widget.ConstraintSet.PARENT_ID;
@@ -28,12 +26,8 @@
 import static com.android.keyguard.KeyguardClockSwitch.SMALL;
 import static com.android.systemui.animation.Interpolators.EMPHASIZED_ACCELERATE;
 import static com.android.systemui.animation.Interpolators.EMPHASIZED_DECELERATE;
-import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
-import static com.android.systemui.classifier.Classifier.GENERIC;
 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
-import static com.android.systemui.classifier.Classifier.UNLOCK;
-import static com.android.systemui.shade.PanelView.DEBUG;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
@@ -46,8 +40,6 @@
 import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPENING;
 import static com.android.systemui.util.DumpUtilsKt.asIndenting;
 
-import static java.lang.Float.isNaN;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -55,8 +47,6 @@
 import android.app.Fragment;
 import android.app.StatusBarManager;
 import android.content.ContentResolver;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -81,13 +71,11 @@
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.MathUtils;
-import android.view.InputDevice;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
 import android.view.ViewStub;
@@ -96,7 +84,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
@@ -110,6 +97,7 @@
 import com.android.internal.policy.SystemBarUtils;
 import com.android.internal.util.LatencyTracker;
 import com.android.keyguard.ActiveUnlockConfig;
+import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.keyguard.KeyguardClockSwitch.ClockSize;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardStatusViewController;
@@ -129,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;
@@ -152,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;
@@ -174,7 +160,6 @@
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
@@ -191,7 +176,6 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
-import com.android.systemui.statusbar.phone.BounceInterpolator;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
@@ -231,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;
@@ -247,25 +230,12 @@
 import javax.inject.Provider;
 
 @CentralSurfacesComponent.CentralSurfacesScope
-public final class NotificationPanelViewController {
-    public static final String TAG = PanelView.class.getSimpleName();
-    public static final float FLING_MAX_LENGTH_SECONDS = 0.6f;
-    public static final float FLING_SPEED_UP_FACTOR = 0.6f;
-    public static final float FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f;
-    public static final float FLING_CLOSING_SPEED_UP_FACTOR = 0.6f;
-    private static final int NO_FIXED_DURATION = -1;
-    private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
-    private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L;
-
-    /**
-     * The factor of the usual high velocity that is needed in order to reach the maximum overshoot
-     * when flinging. A low value will make it that most flings will reach the maximum overshoot.
-     */
-    private static final float FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT = 0.5f;
+public final class NotificationPanelViewController extends PanelViewController {
 
     private static final boolean DEBUG_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
     private static final boolean SPEW_LOGCAT = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
     private static final boolean DEBUG_DRAWABLE = false;
+
     /**
      * The parallax amount of the quick settings translation when dragging down the panel
      */
@@ -274,7 +244,7 @@
     /**
      * Fling expanding QS.
      */
-    private static final int FLING_EXPAND = 0;
+    public static final int FLING_EXPAND = 0;
 
     /**
      * Fling collapsing QS, potentially stopping when QS becomes QQS.
@@ -290,16 +260,6 @@
                     - CollapsedStatusBarFragment.FADE_IN_DURATION
                     - CollapsedStatusBarFragment.FADE_IN_DELAY - 48;
 
-    private final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
-    private final Resources mResources;
-    private final KeyguardStateController mKeyguardStateController;
-    private final SysuiStatusBarStateController mStatusBarStateController;
-    private final AmbientState mAmbientState;
-    private final LockscreenGestureLogger mLockscreenGestureLogger;
-    private final SystemClock mSystemClock;
-
-    private final ShadeLogger mShadeLog;
-
     private final DozeParameters mDozeParameters;
     private final OnHeightChangedListener mOnHeightChangedListener = new OnHeightChangedListener();
     private final Runnable mCollapseExpandAction = new CollapseExpandAction();
@@ -362,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;
@@ -373,28 +330,6 @@
     private final LargeScreenShadeHeaderController mLargeScreenShadeHeaderController;
     private final RecordingController mRecordingController;
     private final PanelEventsEmitter mPanelEventsEmitter;
-    private final boolean mVibrateOnOpening;
-    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
-    private final FlingAnimationUtils mFlingAnimationUtilsClosing;
-    private final FlingAnimationUtils mFlingAnimationUtilsDismissing;
-    private final LatencyTracker mLatencyTracker;
-    private final DozeLog mDozeLog;
-    /** Whether or not the PanelView can be expanded or collapsed with a drag. */
-    private final boolean mNotificationsDragEnabled;
-    private final Interpolator mBounceInterpolator;
-    private final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final PanelExpansionStateManager mPanelExpansionStateManager;
-    private long mDownTime;
-    private boolean mTouchSlopExceededBeforeDown;
-    private boolean mIsLaunchAnimationRunning;
-    private float mOverExpansion;
-    private CentralSurfaces mCentralSurfaces;
-    private HeadsUpManagerPhone mHeadsUpManager;
-    private float mExpandedHeight = 0;
-    private boolean mTracking;
-    private boolean mHintAnimationRunning;
-    private KeyguardBottomAreaView mKeyguardBottomArea;
-    private boolean mExpanding;
     private boolean mSplitShadeEnabled;
     /** The bottom padding reserved for elements of the keyguard measuring notifications. */
     private float mKeyguardNotificationBottomPadding;
@@ -430,7 +365,8 @@
     private boolean mQsTracking;
 
     /**
-     * If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
+     * If set, the ongoing touch gesture might both trigger the expansion in {@link
+     * NotificationPanelView} and
      * the expansion for quick settings.
      */
     private boolean mConflictingQsExpansionGesture;
@@ -576,7 +512,6 @@
                 }
             }).setCustomInterpolator(
                     mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
-    private final NotificationEntryManager mEntryManager;
 
     private final CommandQueue mCommandQueue;
     private final UserManager mUserManager;
@@ -755,53 +690,8 @@
     };
 
     private final CameraGestureHelper mCameraGestureHelper;
-    private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
-    private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
-    private float mMinExpandHeight;
-    private boolean mPanelUpdateWhenAnimatorEnds;
-    private int mFixedDuration = NO_FIXED_DURATION;
-    /** The overshoot amount when the panel flings open */
-    private float mPanelFlingOvershootAmount;
-    /** The amount of pixels that we have overexpanded the last time with a gesture */
-    private float mLastGesturedOverExpansion = -1;
-    /** Is the current animator the spring back animation? */
-    private boolean mIsSpringBackAnimation;
-    private boolean mInSplitShade;
-    private float mHintDistance;
-    private float mInitialOffsetOnTouch;
-    private boolean mCollapsedAndHeadsUpOnDown;
-    private float mExpandedFraction = 0;
-    private float mExpansionDragDownAmountPx = 0;
-    private boolean mPanelClosedOnDown;
-    private boolean mHasLayoutedSinceDown;
-    private float mUpdateFlingVelocity;
-    private boolean mUpdateFlingOnLayout;
-    private boolean mClosing;
-    private boolean mTouchSlopExceeded;
-    private int mTrackingPointer;
-    private int mTouchSlop;
-    private float mSlopMultiplier;
-    private boolean mTouchAboveFalsingThreshold;
-    private boolean mTouchStartedInEmptyArea;
-    private boolean mMotionAborted;
-    private boolean mUpwardsWhenThresholdReached;
-    private boolean mAnimatingOnDown;
-    private boolean mHandlingPointerUp;
-    private ValueAnimator mHeightAnimator;
-    /** Whether instant expand request is currently pending and we are just waiting for layout. */
-    private boolean mInstantExpanding;
-    private boolean mAnimateAfterExpanding;
-    private boolean mIsFlinging;
-    private String mViewName;
-    private float mInitialExpandY;
-    private float mInitialExpandX;
-    private boolean mTouchDisabled;
-    private boolean mInitialTouchFromKeyguard;
-    /** Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time. */
-    private float mNextCollapseSpeedUpFactor = 1.0f;
-    private boolean mGestureWaitForTouchSlop;
-    private boolean mIgnoreXTouchSlop;
-    private boolean mExpandLatencyTracking;
+    private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
+    private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
 
     @Inject
     public NotificationPanelViewController(NotificationPanelView view,
@@ -812,7 +702,6 @@
             DynamicPrivacyController dynamicPrivacyController,
             KeyguardBypassController bypassController, FalsingManager falsingManager,
             FalsingCollector falsingCollector,
-            NotificationEntryManager notificationEntryManager,
             KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
             StatusBarWindowStateController statusBarWindowStateController,
@@ -825,7 +714,7 @@
             MetricsLogger metricsLogger,
             ShadeLogger shadeLogger,
             ConfigurationController configurationController,
-            Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilderProvider,
+            Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
             StatusBarTouchableRegionManager statusBarTouchableRegionManager,
             ConversationNotificationManager conversationNotificationManager,
             MediaHierarchyManager mediaHierarchyManager,
@@ -851,8 +740,6 @@
             NavigationModeController navigationModeController,
             FragmentService fragmentService,
             ContentResolver contentResolver,
-            QuickAccessWalletController quickAccessWalletController,
-            QRCodeScannerController qrCodeScannerController,
             RecordingController recordingController,
             LargeScreenShadeHeaderController largeScreenShadeHeaderController,
             ScreenOffAnimationController screenOffAnimationController,
@@ -860,7 +747,6 @@
             PanelExpansionStateManager panelExpansionStateManager,
             NotificationRemoteInputManager remoteInputManager,
             Optional<SysUIUnfoldComponent> unfoldComponent,
-            ControlsComponent controlsComponent,
             InteractionJankMonitor interactionJankMonitor,
             QsFrameTranslateController qsFrameTranslateController,
             SysUiState sysUiState,
@@ -873,79 +759,34 @@
             ShadeTransitionController shadeTransitionController,
             SystemClock systemClock,
             CameraGestureHelper cameraGestureHelper,
-            Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
-            Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
-        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
-            @Override
-            public void onKeyguardFadingAwayChanged() {
-                requestPanelHeightUpdate();
-            }
-        });
-        mAmbientState = ambientState;
+            KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
+            KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) {
+        super(view,
+                falsingManager,
+                dozeLog,
+                keyguardStateController,
+                (SysuiStatusBarStateController) statusBarStateController,
+                notificationShadeWindowController,
+                vibratorHelper,
+                statusBarKeyguardViewManager,
+                latencyTracker,
+                flingAnimationUtilsBuilder.get(),
+                statusBarTouchableRegionManager,
+                lockscreenGestureLogger,
+                panelExpansionStateManager,
+                ambientState,
+                interactionJankMonitor,
+                shadeLogger,
+                systemClock);
         mView = view;
-        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
-        mLockscreenGestureLogger = lockscreenGestureLogger;
-        mPanelExpansionStateManager = panelExpansionStateManager;
-        mShadeLog = shadeLogger;
-        TouchHandler touchHandler = createTouchHandler();
-        mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
-            @Override
-            public void onViewAttachedToWindow(View v) {
-                mViewName = mResources.getResourceName(mView.getId());
-            }
-
-            @Override
-            public void onViewDetachedFromWindow(View v) {
-            }
-        });
-
-        mView.addOnLayoutChangeListener(createLayoutChangeListener());
-        mView.setOnTouchListener(touchHandler);
-        mView.setOnConfigurationChangedListener(createOnConfigurationChangedListener());
-
-        mResources = mView.getResources();
-        mKeyguardStateController = keyguardStateController;
-        mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
-        mNotificationShadeWindowController = notificationShadeWindowController;
-        FlingAnimationUtils.Builder flingAnimationUtilsBuilder =
-                flingAnimationUtilsBuilderProvider.get();
-        mFlingAnimationUtils = flingAnimationUtilsBuilder
-                .reset()
-                .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS)
-                .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
-                .build();
-        mFlingAnimationUtilsClosing = flingAnimationUtilsBuilder
-                .reset()
-                .setMaxLengthSeconds(FLING_CLOSING_MAX_LENGTH_SECONDS)
-                .setSpeedUpFactor(FLING_CLOSING_SPEED_UP_FACTOR)
-                .build();
-        mFlingAnimationUtilsDismissing = flingAnimationUtilsBuilder
-                .reset()
-                .setMaxLengthSeconds(0.5f)
-                .setSpeedUpFactor(0.6f)
-                .setX2(0.6f)
-                .setY2(0.84f)
-                .build();
-        mLatencyTracker = latencyTracker;
-        mBounceInterpolator = new BounceInterpolator();
-        mFalsingManager = falsingManager;
-        mDozeLog = dozeLog;
-        mNotificationsDragEnabled = mResources.getBoolean(
-                R.bool.config_enableNotificationShadeDrag);
         mVibratorHelper = vibratorHelper;
-        mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation);
-        mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
-        mInteractionJankMonitor = interactionJankMonitor;
-        mSystemClock = systemClock;
         mKeyguardMediaController = keyguardMediaController;
         mPrivacyDotViewController = privacyDotViewController;
-        mQuickAccessWalletController = quickAccessWalletController;
-        mQRCodeScannerController = qrCodeScannerController;
-        mControlsComponent = controlsComponent;
         mMetricsLogger = metricsLogger;
         mConfigurationController = configurationController;
-        mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilderProvider;
+        mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
         mMediaHierarchyManager = mediaHierarchyManager;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mNotificationsQSContainerController = notificationsQSContainerController;
         mNotificationListContainer = notificationListContainer;
         mNotificationStackSizeCalculator = notificationStackSizeCalculator;
@@ -967,6 +808,7 @@
         mLargeScreenShadeHeaderController = largeScreenShadeHeaderController;
         mLayoutInflater = layoutInflater;
         mFeatureFlags = featureFlags;
+        mFalsingManager = falsingManager;
         mFalsingCollector = falsingCollector;
         mPowerManager = powerManager;
         mWakeUpCoordinator = coordinator;
@@ -982,6 +824,7 @@
         mUserManager = userManager;
         mMediaDataManager = mediaDataManager;
         mTapAgainViewController = tapAgainViewController;
+        mInteractionJankMonitor = interactionJankMonitor;
         mSysUiState = sysUiState;
         mPanelEventsEmitter = panelEventsEmitter;
         pulseExpansionHandler.setPulseExpandAbortListener(() -> {
@@ -1010,7 +853,6 @@
         });
         mBottomAreaShadeAlphaAnimator.setDuration(160);
         mBottomAreaShadeAlphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
-        mEntryManager = notificationEntryManager;
         mConversationNotificationManager = conversationNotificationManager;
         mAuthController = authController;
         mLockIconViewController = lockIconViewController;
@@ -1043,7 +885,7 @@
 
         mQsFrameTranslateController = qsFrameTranslateController;
         updateUserSwitcherFlags();
-        mKeyguardBottomAreaViewModelProvider = keyguardBottomAreaViewModelProvider;
+        mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
         onFinishInflate();
         keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
                 new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -1097,7 +939,7 @@
                     }
                 });
         mCameraGestureHelper = cameraGestureHelper;
-        mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
+        mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
     }
 
     @VisibleForTesting
@@ -1184,14 +1026,9 @@
                 controller.setup(mNotificationContainerParent));
     }
 
-    @VisibleForTesting
-    void loadDimens() {
-        final ViewConfiguration configuration = ViewConfiguration.get(this.mView.getContext());
-        mTouchSlop = configuration.getScaledTouchSlop();
-        mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
-        mHintDistance = mResources.getDimension(R.dimen.hint_move_distance);
-        mPanelFlingOvershootAmount = mResources.getDimension(R.dimen.panel_overshoot_amount);
-        mInSplitShade = mResources.getBoolean(R.bool.config_use_split_notification_shade);
+    @Override
+    protected void loadDimens() {
+        super.loadDimens();
         mFlingAnimationUtils = mFlingAnimationUtilsBuilder.get()
                 .setMaxLengthSeconds(0.4f).build();
         mStatusBarMinHeight = SystemBarUtils.getStatusBarHeight(mView.getContext());
@@ -1427,17 +1264,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
@@ -1493,6 +1320,9 @@
         mIsFullWidth = isFullWidth;
         mScrimController.setClipsQsScrim(isFullWidth);
         mNotificationStackScrollLayoutController.setIsFullWidth(isFullWidth);
+        if (mQs != null) {
+            mQs.setIsNotificationPanelFullWidth(isFullWidth);
+        }
     }
 
     private void startQsSizeChangeAnimation(int oldHeight, final int newHeight) {
@@ -1554,7 +1384,6 @@
         }
 
         mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
-        mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
 
         mStackScrollerMeasuringPass++;
         requestScrollerTopPaddingUpdate(animate);
@@ -1604,7 +1433,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;
@@ -1875,6 +1704,7 @@
         }
     }
 
+    @Override
     public void collapse(boolean delayed, float speedUpFactor) {
         if (!canPanelBeCollapsed()) {
             return;
@@ -1884,20 +1714,7 @@
             setQsExpandImmediate(true);
             setShowShelfOnly(true);
         }
-        if (DEBUG) this.logf("collapse: " + this);
-        if (canPanelBeCollapsed()) {
-            cancelHeightAnimator();
-            notifyExpandingStarted();
-
-            // Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
-            setIsClosing(true);
-            if (delayed) {
-                mNextCollapseSpeedUpFactor = speedUpFactor;
-                this.mView.postDelayed(mFlingCollapseRunnable, 120);
-            } else {
-                fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */);
-            }
-        }
+        super.collapse(delayed, speedUpFactor);
     }
 
     private void setQsExpandImmediate(boolean expandImmediate) {
@@ -1915,15 +1732,10 @@
         setQsExpansion(mQsMinExpansionHeight);
     }
 
+    @Override
     @VisibleForTesting
-    void cancelHeightAnimator() {
-        if (mHeightAnimator != null) {
-            if (mHeightAnimator.isRunning()) {
-                mPanelUpdateWhenAnimatorEnds = false;
-            }
-            mHeightAnimator.cancel();
-        }
-        endClosing();
+    protected void cancelHeightAnimator() {
+        super.cancelHeightAnimator();
     }
 
     public void cancelAnimation() {
@@ -1991,123 +1803,28 @@
         }
     }
 
+    @Override
     public void fling(float vel, boolean expand) {
         GestureRecorder gr = mCentralSurfaces.getGestureRecorder();
         if (gr != null) {
             gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
         }
-        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, false);
+        super.fling(vel, expand);
     }
 
-    @VisibleForTesting
-    void flingToHeight(float vel, boolean expand, float target,
+    @Override
+    protected void flingToHeight(float vel, boolean expand, float target,
             float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
         mHeadsUpTouchHelper.notifyFling(!expand);
         mKeyguardStateController.notifyPanelFlingStart(!expand /* flingingToDismiss */);
         setClosingWithAlphaFadeout(!expand && !isOnKeyguard() && getFadeoutAlpha() == 1.0f);
         mNotificationStackScrollLayoutController.setPanelFlinging(true);
-        if (target == mExpandedHeight && mOverExpansion == 0.0f) {
-            // We're at the target and didn't fling and there's no overshoot
-            onFlingEnd(false /* cancelled */);
-            return;
-        }
-        mIsFlinging = true;
-        // we want to perform an overshoot animation when flinging open
-        final boolean addOverscroll =
-                expand
-                        && !mInSplitShade // Split shade has its own overscroll logic
-                        && mStatusBarStateController.getState() != KEYGUARD
-                        && mOverExpansion == 0.0f
-                        && vel >= 0;
-        final boolean shouldSpringBack = addOverscroll || (mOverExpansion != 0.0f && expand);
-        float overshootAmount = 0.0f;
-        if (addOverscroll) {
-            // Let's overshoot depending on the amount of velocity
-            overshootAmount = MathUtils.lerp(
-                    0.2f,
-                    1.0f,
-                    MathUtils.saturate(vel
-                            / (this.mFlingAnimationUtils.getHighVelocityPxPerSecond()
-                            * FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT)));
-            overshootAmount += mOverExpansion / mPanelFlingOvershootAmount;
-        }
-        ValueAnimator animator = createHeightAnimator(target, overshootAmount);
-        if (expand) {
-            if (expandBecauseOfFalsing && vel < 0) {
-                vel = 0;
-            }
-            this.mFlingAnimationUtils.apply(animator, mExpandedHeight,
-                    target + overshootAmount * mPanelFlingOvershootAmount, vel,
-                    this.mView.getHeight());
-            if (vel == 0) {
-                animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION);
-            }
-        } else {
-            if (shouldUseDismissingAnimation()) {
-                if (vel == 0) {
-                    animator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED);
-                    long duration = (long) (200 + mExpandedHeight / this.mView.getHeight() * 100);
-                    animator.setDuration(duration);
-                } else {
-                    mFlingAnimationUtilsDismissing.apply(animator, mExpandedHeight, target, vel,
-                            this.mView.getHeight());
-                }
-            } else {
-                mFlingAnimationUtilsClosing.apply(
-                        animator, mExpandedHeight, target, vel, this.mView.getHeight());
-            }
-
-            // Make it shorter if we run a canned animation
-            if (vel == 0) {
-                animator.setDuration((long) (animator.getDuration() / collapseSpeedUpFactor));
-            }
-            if (mFixedDuration != NO_FIXED_DURATION) {
-                animator.setDuration(mFixedDuration);
-            }
-        }
-        animator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationStart(Animator animation) {
-                if (!mStatusBarStateController.isDozing()) {
-                    beginJankMonitoring();
-                }
-            }
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (shouldSpringBack && !mCancelled) {
-                    // After the shade is flinged open to an overscrolled state, spring back
-                    // the shade by reducing section padding to 0.
-                    springBack();
-                } else {
-                    onFlingEnd(mCancelled);
-                }
-            }
-        });
-        setAnimator(animator);
-        animator.start();
+        super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
     }
 
-    private void onFlingEnd(boolean cancelled) {
-        mIsFlinging = false;
-        // No overshoot when the animation ends
-        setOverExpansionInternal(0, false /* isFromGesture */);
-        setAnimator(null);
-        mKeyguardStateController.notifyPanelFlingEnd();
-        if (!cancelled) {
-            endJankMonitoring();
-            notifyExpandingFinished();
-        } else {
-            cancelJankMonitoring();
-        }
-        updatePanelExpansionAndVisibility();
+    @Override
+    protected void onFlingEnd(boolean cancelled) {
+        super.onFlingEnd(cancelled);
         mNotificationStackScrollLayoutController.setPanelFlinging(false);
     }
 
@@ -2202,7 +1919,8 @@
         return mQsTracking;
     }
 
-    private boolean isInContentBounds(float x, float y) {
+    @Override
+    protected boolean isInContentBounds(float x, float y) {
         float stackScrollerX = mNotificationStackScrollLayoutController.getX();
         return !mNotificationStackScrollLayoutController
                 .isBelowLastNotification(x - stackScrollerX, y)
@@ -2335,8 +2053,9 @@
                         - mQsMinExpansionHeight));
     }
 
-    private boolean shouldExpandWhenNotFlinging() {
-        if (getExpandedFraction() > 0.5f) {
+    @Override
+    protected boolean shouldExpandWhenNotFlinging() {
+        if (super.shouldExpandWhenNotFlinging()) {
             return true;
         }
         if (mAllowExpandForSmallExpansion) {
@@ -2348,7 +2067,8 @@
         return false;
     }
 
-    private float getOpeningHeight() {
+    @Override
+    protected float getOpeningHeight() {
         return mNotificationStackScrollLayoutController.getOpeningHeight();
     }
 
@@ -2498,20 +2218,9 @@
         }
     }
 
-    private boolean flingExpands(float vel, float vectorVel, float x, float y) {
-        boolean expands = true;
-        if (!this.mFalsingManager.isUnlockingDisabled()) {
-            @Classifier.InteractionType int interactionType = y - mInitialExpandY > 0
-                    ? QUICK_SETTINGS : (
-                    mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
-            if (!isFalseTouch(x, y, interactionType)) {
-                if (Math.abs(vectorVel) < this.mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
-                    expands = shouldExpandWhenNotFlinging();
-                } else {
-                    expands = vel > 0;
-                }
-            }
-        }
+    @Override
+    protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
+        boolean expands = super.flingExpands(vel, vectorVel, x, y);
 
         // If we are already running a QS expansion, make sure that we keep the panel open.
         if (mQsExpansionAnimator != null) {
@@ -2520,7 +2229,8 @@
         return expands;
     }
 
-    private boolean shouldGestureWaitForTouchSlop() {
+    @Override
+    protected boolean shouldGestureWaitForTouchSlop() {
         if (mExpectingSynthesizedDown) {
             mExpectingSynthesizedDown = false;
             return false;
@@ -2598,7 +2308,7 @@
         }
     }
 
-    private int getFalsingThreshold() {
+    protected int getFalsingThreshold() {
         float factor = mCentralSurfaces.isWakeUpComingFromTouch() ? 1.5f : 1.0f;
         return (int) (mQsFalsingThreshold * factor);
     }
@@ -2622,7 +2332,7 @@
         // When expanding QS, let's authenticate the user if possible,
         // this will speed up notification actions.
         if (height == 0) {
-            mCentralSurfaces.requestFaceAuth(false);
+            mCentralSurfaces.requestFaceAuth(false, FaceAuthApiRequestReason.QS_EXPANDED);
         }
     }
 
@@ -2721,8 +2431,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();
@@ -3332,8 +3042,8 @@
         }
     }
 
-    @VisibleForTesting
-    boolean canCollapsePanelOnTouch() {
+    @Override
+    protected boolean canCollapsePanelOnTouch() {
         if (!isInSettings() && mBarState == KEYGUARD) {
             return true;
         }
@@ -3345,6 +3055,7 @@
         return !mSplitShadeEnabled && (isInSettings() || mIsPanelCollapseOnQQS);
     }
 
+    @Override
     public int getMaxPanelHeight() {
         int min = mStatusBarMinHeight;
         if (!(mBarState == KEYGUARD)
@@ -3387,7 +3098,8 @@
         return mIsExpanding;
     }
 
-    private void onHeightUpdated(float expandedHeight) {
+    @Override
+    protected void onHeightUpdated(float expandedHeight) {
         if (!mQsExpanded || mQsExpandImmediate || mIsExpanding && mQsExpandedWhenExpandingStarted) {
             // Updating the clock position will set the top padding which might
             // trigger a new panel height and re-position the clock.
@@ -3564,12 +3276,13 @@
                 getExpandedFraction());
         float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
         alpha *= mBottomAreaShadeAlpha;
-        mKeyguardBottomArea.setComponentAlphas(alpha);
-        mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
+        mKeyguardBottomAreaInteractor.setAlpha(alpha);
         mLockIconViewController.setAlpha(alpha);
     }
 
-    private void onExpandingStarted() {
+    @Override
+    protected void onExpandingStarted() {
+        super.onExpandingStarted();
         mNotificationStackScrollLayoutController.onExpansionStarted();
         mIsExpanding = true;
         mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
@@ -3585,7 +3298,8 @@
         mQs.setHeaderListening(true);
     }
 
-    private void onExpandingFinished() {
+    @Override
+    protected void onExpandingFinished() {
         mScrimController.onExpandingFinished();
         mNotificationStackScrollLayoutController.onExpansionStopped();
         mHeadsUpManager.onExpandingFinished();
@@ -3633,54 +3347,18 @@
         mQs.setListening(listening);
     }
 
+    @Override
     public void expand(boolean animate) {
-        if (isFullyCollapsed() || isCollapsing()) {
-            mInstantExpanding = true;
-            mAnimateAfterExpanding = animate;
-            mUpdateFlingOnLayout = false;
-            abortAnimations();
-            if (mTracking) {
-                onTrackingStopped(true /* expands */); // The panel is expanded after this call.
-            }
-            if (mExpanding) {
-                notifyExpandingFinished();
-            }
-            updatePanelExpansionAndVisibility();// Wait for window manager to pickup the change,
-            // so we know the maximum height of the panel then.
-            this.mView.getViewTreeObserver().addOnGlobalLayoutListener(
-                new ViewTreeObserver.OnGlobalLayoutListener() {
-                    @Override
-                    public void onGlobalLayout() {
-                        if (!mInstantExpanding) {
-                            mView.getViewTreeObserver().removeOnGlobalLayoutListener(
-                                    this);
-                            return;
-                        }
-                        if (mCentralSurfaces.getNotificationShadeWindowView().isVisibleToUser()) {
-                            mView.getViewTreeObserver().removeOnGlobalLayoutListener(
-                                    this);
-                            if (mAnimateAfterExpanding) {
-                                notifyExpandingStarted();
-                                beginJankMonitoring();
-                                fling(0, true /* expand */);
-                            } else {
-                                setExpandedFraction(1f);
-                            }
-                            mInstantExpanding = false;
-                        }
-                    }
-                });// Make sure a layout really happens.
-            this.mView.requestLayout();
-        }
-
+        super.expand(animate);
         setListening(true);
     }
 
+    @Override
     public void setOverExpansion(float overExpansion) {
         if (overExpansion == mOverExpansion) {
             return;
         }
-        mOverExpansion = overExpansion;
+        super.setOverExpansion(overExpansion);
         // Translating the quick settings by half the overexpansion to center it in the background
         // frame
         updateQsFrameTranslation();
@@ -3692,13 +3370,10 @@
                 mQsTranslationForFullShadeTransition);
     }
 
-    private void onTrackingStarted() {
+    @Override
+    protected void onTrackingStarted() {
         mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
-        endClosing();
-        mTracking = true;
-        mCentralSurfaces.onTrackingStarted();
-        notifyExpandingStarted();
-        updatePanelExpansionAndVisibility();
+        super.onTrackingStarted();
         mScrimController.onTrackingStarted();
         if (mQsFullyExpanded) {
             setQsExpandImmediate(true);
@@ -3708,11 +3383,10 @@
         cancelPendingPanelCollapse();
     }
 
-    private void onTrackingStopped(boolean expand) {
+    @Override
+    protected void onTrackingStopped(boolean expand) {
         mFalsingCollector.onTrackingStopped();
-        mTracking = false;
-        mCentralSurfaces.onTrackingStopped(expand);
-        updatePanelExpansionAndVisibility();
+        super.onTrackingStopped(expand);
         if (expand) {
             mNotificationStackScrollLayoutController.setOverScrollAmount(0.0f, true /* onTop */,
                     true /* animate */);
@@ -3729,50 +3403,38 @@
                 getHeight(), mNavigationBarBottomHeight);
     }
 
-    @VisibleForTesting
-    void startUnlockHintAnimation() {
+    @Override
+    protected void startUnlockHintAnimation() {
         if (mPowerManager.isPowerSaveMode() || mAmbientState.getDozeAmount() > 0f) {
             onUnlockHintStarted();
             onUnlockHintFinished();
             return;
         }
-
-        // We don't need to hint the user if an animation is already running or the user is changing
-        // the expansion.
-        if (mHeightAnimator != null || mTracking) {
-            return;
-        }
-        notifyExpandingStarted();
-        startUnlockHintAnimationPhase1(() -> {
-            notifyExpandingFinished();
-            onUnlockHintFinished();
-            mHintAnimationRunning = false;
-        });
-        onUnlockHintStarted();
-        mHintAnimationRunning = true;
+        super.startUnlockHintAnimation();
     }
 
-    @VisibleForTesting
-    void onUnlockHintFinished() {
-        mCentralSurfaces.onHintFinished();
+    @Override
+    protected void onUnlockHintFinished() {
+        super.onUnlockHintFinished();
         mScrimController.setExpansionAffectsAlpha(true);
         mNotificationStackScrollLayoutController.setUnlockHintRunning(false);
     }
 
-    @VisibleForTesting
-    void onUnlockHintStarted() {
-        mCentralSurfaces.onUnlockHintStarted();
+    @Override
+    protected void onUnlockHintStarted() {
+        super.onUnlockHintStarted();
         mScrimController.setExpansionAffectsAlpha(false);
         mNotificationStackScrollLayoutController.setUnlockHintRunning(true);
     }
 
-    private boolean shouldUseDismissingAnimation() {
+    @Override
+    protected boolean shouldUseDismissingAnimation() {
         return mBarState != StatusBarState.SHADE && (mKeyguardStateController.canDismissLockScreen()
                 || !isTracking());
     }
 
-    @VisibleForTesting
-    boolean isTrackingBlocked() {
+    @Override
+    protected boolean isTrackingBlocked() {
         return mConflictingQsExpansionGesture && mQsExpanded || mBlockingExpansionForCurrentTouch;
     }
 
@@ -3794,30 +3456,32 @@
         return mIsLaunchTransitionFinished;
     }
 
+    @Override
     public void setIsLaunchAnimationRunning(boolean running) {
         boolean wasRunning = mIsLaunchAnimationRunning;
-        mIsLaunchAnimationRunning = running;
+        super.setIsLaunchAnimationRunning(running);
         if (wasRunning != mIsLaunchAnimationRunning) {
             mPanelEventsEmitter.notifyLaunchingActivityChanged(running);
         }
     }
 
-    private void setIsClosing(boolean isClosing) {
+    @Override
+    protected void setIsClosing(boolean isClosing) {
         boolean wasClosing = isClosing();
-        mClosing = isClosing;
+        super.setIsClosing(isClosing);
         if (wasClosing != isClosing) {
             mPanelEventsEmitter.notifyPanelCollapsingChanged(isClosing);
         }
     }
 
     private void updateDozingVisibilities(boolean animate) {
-        mKeyguardBottomArea.setDozing(mDozing, animate);
-        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+        mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
         if (!mDozing && animate) {
             mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
         }
     }
 
+    @Override
     public boolean isDozing() {
         return mDozing;
     }
@@ -3834,7 +3498,8 @@
         mKeyguardStatusViewController.dozeTimeTick();
     }
 
-    private boolean onMiddleClicked() {
+    @Override
+    protected boolean onMiddleClicked() {
         switch (mBarState) {
             case KEYGUARD:
                 if (!mDozingOnDown) {
@@ -3842,7 +3507,8 @@
                             && !mUpdateMonitor.isFaceDetectionRunning()
                             && !mUpdateMonitor.getUserCanSkipBouncer(
                             KeyguardUpdateMonitor.getCurrentUser())) {
-                        mUpdateMonitor.requestFaceAuth(true);
+                        mUpdateMonitor.requestFaceAuth(true,
+                                FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED);
                     } else {
                         mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT,
                                 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
@@ -3892,13 +3558,15 @@
         updateVisibility();
     }
 
-    private boolean shouldPanelBeVisible() {
+    @Override
+    protected boolean shouldPanelBeVisible() {
         boolean headsUpVisible = mHeadsUpAnimatingAway || mHeadsUpPinnedMode;
         return headsUpVisible || isExpanded() || mBouncerShowing;
     }
 
+    @Override
     public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
-        mHeadsUpManager = headsUpManager;
+        super.setHeadsUpManager(headsUpManager);
         mHeadsUpTouchHelper = new HeadsUpTouchHelper(headsUpManager,
                 mNotificationStackScrollLayoutController.getHeadsUpCallback(),
                 NotificationPanelViewController.this);
@@ -3912,7 +3580,8 @@
         // otherwise we update the state when the expansion is finished
     }
 
-    private void onClosingFinished() {
+    @Override
+    protected void onClosingFinished() {
         mCentralSurfaces.onClosingFinished();
         setClosingWithAlphaFadeout(false);
         mMediaHierarchyManager.closeGuts();
@@ -3976,7 +3645,8 @@
         mCentralSurfaces.clearNotificationEffects();
     }
 
-    private boolean isPanelVisibleBecauseOfHeadsUp() {
+    @Override
+    protected boolean isPanelVisibleBecauseOfHeadsUp() {
         return (mHeadsUpManager.hasPinnedHeadsUp() || mHeadsUpAnimatingAway)
                 && mBarState == StatusBarState.SHADE;
     }
@@ -4049,6 +3719,7 @@
             mQs.setHeaderClickable(isQsExpansionEnabled());
             mQs.setOverscrolling(mStackScrollerOverscrolling);
             mQs.setInSplitShade(mSplitShadeEnabled);
+            mQs.setIsNotificationPanelFullWidth(mIsFullWidth);
 
             // recompute internal state when qspanel height changes
             mQs.getView().addOnLayoutChangeListener(
@@ -4090,15 +3761,9 @@
         mNotificationBoundsAnimationDelay = delay;
     }
 
+    @Override
     public void setTouchAndAnimationDisabled(boolean disabled) {
-        mTouchDisabled = disabled;
-        if (mTouchDisabled) {
-            cancelHeightAnimator();
-            if (mTracking) {
-                onTrackingStopped(true /* expanded */);
-            }
-            notifyExpandingFinished();
-        }
+        super.setTouchAndAnimationDisabled(disabled);
         mNotificationStackScrollLayoutController.setAnimationsEnabled(!disabled);
     }
 
@@ -4113,8 +3778,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) {
@@ -4163,7 +3827,6 @@
 
     public void dozeTimeTick() {
         mLockIconViewController.dozeTimeTick();
-        mKeyguardBottomArea.dozeTimeTick();
         mKeyguardStatusViewController.dozeTimeTick();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
@@ -4300,14 +3963,9 @@
         mBlockingExpansionForCurrentTouch = mTracking;
     }
 
+    @Override
     public void dump(PrintWriter pw, String[] args) {
-        pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s"
-                        + " tracking=%s timeAnim=%s%s "
-                        + "touchDisabled=%s" + "]",
-                this.getClass().getSimpleName(), getExpandedHeight(), getMaxPanelHeight(),
-                mClosing ? "T" : "f", mTracking ? "T" : "f", mHeightAnimator,
-                ((mHeightAnimator != null && mHeightAnimator.isStarted()) ? " (started)" : ""),
-                mTouchDisabled ? "T" : "f"));
+        super.dump(pw, args);
         IndentingPrintWriter ipw = asIndenting(pw);
         ipw.increaseIndent();
         ipw.println("gestureExclusionRect:" + calculateGestureExclusionRect());
@@ -4450,359 +4108,127 @@
         mConfigurationListener.onThemeChanged();
     }
 
-    private OnLayoutChangeListener createLayoutChangeListener() {
-        return new OnLayoutChangeListener();
+    @Override
+    protected OnLayoutChangeListener createLayoutChangeListener() {
+        return new OnLayoutChangeListenerImpl();
     }
 
-    @VisibleForTesting
-    TouchHandler createTouchHandler() {
-        return new TouchHandler();
-    }
+    @Override
+    protected TouchHandler createTouchHandler() {
+        return new TouchHandler() {
 
-    public class TouchHandler implements View.OnTouchListener {
+            private long mLastTouchDownTime = -1L;
 
-        private long mLastTouchDownTime = -1L;
-
-        public boolean onInterceptTouchEvent(MotionEvent event) {
-            if (SPEW_LOGCAT) {
-                Log.v(TAG,
-                        "NPVC onInterceptTouchEvent (" + event.getId() + "): (" + event.getX()
-                                + "," + event.getY() + ")");
-            }
-            if (mBlockTouches || mQs.disallowPanelTouches()) {
-                return false;
-            }
-            initDownStates(event);
-            // Do not let touches go to shade or QS if the bouncer is visible,
-            // but still let user swipe down to expand the panel, dismissing the bouncer.
-            if (mCentralSurfaces.isBouncerShowing()) {
-                return true;
-            }
-            if (mCommandQueue.panelsEnabled()
-                    && !mNotificationStackScrollLayoutController.isLongPressInProgress()
-                    && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
-                mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
-                mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
-                return true;
-            }
-            if (!shouldQuickSettingsIntercept(mDownX, mDownY, 0)
-                    && mPulseExpansionHandler.onInterceptTouchEvent(event)) {
-                return true;
-            }
-
-            if (!isFullyCollapsed() && onQsIntercept(event)) {
-                if (DEBUG_LOGCAT) Log.d(TAG, "onQsIntercept true");
-                return true;
-            }
-            if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
-                    && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
-                return false;
-            }
-
-            /*
-             * If the user drags anywhere inside the panel we intercept it if the movement is
-             * upwards. This allows closing the shade from anywhere inside the panel.
-             *
-             * We only do this if the current content is scrolled to the bottom,
-             * i.e. canCollapsePanelOnTouch() is true and therefore there is no conflicting
-             * scrolling gesture possible.
-             */
-            int pointerIndex = event.findPointerIndex(mTrackingPointer);
-            if (pointerIndex < 0) {
-                pointerIndex = 0;
-                mTrackingPointer = event.getPointerId(pointerIndex);
-            }
-            final float x = event.getX(pointerIndex);
-            final float y = event.getY(pointerIndex);
-            boolean canCollapsePanel = canCollapsePanelOnTouch();
-
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    mCentralSurfaces.userActivity();
-                    mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation;
-                    mMinExpandHeight = 0.0f;
-                    mDownTime = mSystemClock.uptimeMillis();
-                    if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) {
-                        cancelHeightAnimator();
-                        mTouchSlopExceeded = true;
-                        return true;
-                    }
-                    mInitialExpandY = y;
-                    mInitialExpandX = x;
-                    mTouchStartedInEmptyArea = !isInContentBounds(x, y);
-                    mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
-                    mMotionAborted = false;
-                    mPanelClosedOnDown = isFullyCollapsed();
-                    mCollapsedAndHeadsUpOnDown = false;
-                    mHasLayoutedSinceDown = false;
-                    mUpdateFlingOnLayout = false;
-                    mTouchAboveFalsingThreshold = false;
-                    addMovement(event);
-                    break;
-                case MotionEvent.ACTION_POINTER_UP:
-                    final int upPointer = event.getPointerId(event.getActionIndex());
-                    if (mTrackingPointer == upPointer) {
-                        // gesture is ongoing, find a new pointer to track
-                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
-                        mTrackingPointer = event.getPointerId(newIndex);
-                        mInitialExpandX = event.getX(newIndex);
-                        mInitialExpandY = event.getY(newIndex);
-                    }
-                    break;
-                case MotionEvent.ACTION_POINTER_DOWN:
-                    if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
-                        mMotionAborted = true;
-                        mVelocityTracker.clear();
-                    }
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    final float h = y - mInitialExpandY;
-                    addMovement(event);
-                    final boolean openShadeWithoutHun =
-                            mPanelClosedOnDown && !mCollapsedAndHeadsUpOnDown;
-                    if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown
-                            || openShadeWithoutHun) {
-                        float hAbs = Math.abs(h);
-                        float touchSlop = getTouchSlop(event);
-                        if ((h < -touchSlop
-                                || ((openShadeWithoutHun || mAnimatingOnDown) && hAbs > touchSlop))
-                                && hAbs > Math.abs(x - mInitialExpandX)) {
-                            cancelHeightAnimator();
-                            startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
-                            return true;
-                        }
-                    }
-                    break;
-                case MotionEvent.ACTION_CANCEL:
-                case MotionEvent.ACTION_UP:
-                    mVelocityTracker.clear();
-                    break;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                if (event.getDownTime() == mLastTouchDownTime) {
-                    // An issue can occur when swiping down after unlock, where multiple down
-                    // events are received in this handler with identical downTimes. Until the
-                    // source of the issue can be located, detect this case and ignore.
-                    // see b/193350347
-                    Log.w(TAG, "Duplicate down event detected... ignoring");
+            @Override
+            public boolean onInterceptTouchEvent(MotionEvent event) {
+                if (SPEW_LOGCAT) {
+                    Log.v(TAG,
+                            "NPVC onInterceptTouchEvent (" + event.getId() + "): (" + event.getX()
+                                    + "," + event.getY() + ")");
+                }
+                if (mBlockTouches || mQs.disallowPanelTouches()) {
+                    return false;
+                }
+                initDownStates(event);
+                // Do not let touches go to shade or QS if the bouncer is visible,
+                // but still let user swipe down to expand the panel, dismissing the bouncer.
+                if (mCentralSurfaces.isBouncerShowing()) {
                     return true;
                 }
-                mLastTouchDownTime = event.getDownTime();
-            }
-
-
-            if (mBlockTouches || (mQsFullyExpanded && mQs != null && mQs.disallowPanelTouches())) {
-                return false;
-            }
-
-            // Do not allow panel expansion if bouncer is scrimmed or showing over a dream,
-            // otherwise user would be able to pull down QS or expand the shade.
-            if (mCentralSurfaces.isBouncerShowingScrimmed()
-                    || mCentralSurfaces.isBouncerShowingOverDream()) {
-                return false;
-            }
-
-            // Make sure the next touch won't the blocked after the current ends.
-            if (event.getAction() == MotionEvent.ACTION_UP
-                    || event.getAction() == MotionEvent.ACTION_CANCEL) {
-                mBlockingExpansionForCurrentTouch = false;
-            }
-            // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
-            // without any ACTION_MOVE event.
-            // In such case, simply expand the panel instead of being stuck at the bottom bar.
-            if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
-                expand(true /* animate */);
-            }
-            initDownStates(event);
-
-            // If pulse is expanding already, let's give it the touch. There are situations
-            // where the panel starts expanding even though we're also pulsing
-            boolean pulseShouldGetTouch = (!mIsExpanding
-                    && !shouldQuickSettingsIntercept(mDownX, mDownY, 0))
-                    || mPulseExpansionHandler.isExpanding();
-            if (pulseShouldGetTouch && mPulseExpansionHandler.onTouchEvent(event)) {
-                // We're expanding all the other ones shouldn't get this anymore
-                mShadeLog.logMotionEvent(event, "onTouch: PulseExpansionHandler handled event");
-                return true;
-            }
-            if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
-                    && !mNotificationStackScrollLayoutController.isLongPressInProgress()
-                    && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
-                mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
-            }
-            boolean handled = mHeadsUpTouchHelper.onTouchEvent(event);
-
-            if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
-                mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
-                return true;
-            }
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
-                mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
-                handled = true;
-            }
-
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyExpanded()
-                    && mStatusBarKeyguardViewManager.isShowing()) {
-                mStatusBarKeyguardViewManager.updateKeyguardPosition(event.getX());
-            }
-            handled |= handleTouch(v, event);
-            return !mDozing || mPulsing || handled;
-        }
-
-        public boolean handleTouch(View v, MotionEvent event) {
-            if (mInstantExpanding) {
-                mShadeLog.logMotionEvent(event, "onTouch: touch ignored due to instant expanding");
-                return false;
-            }
-            if (mTouchDisabled  && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
-                mShadeLog.logMotionEvent(event, "onTouch: non-cancel action, touch disabled");
-                return false;
-            }
-            if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
-                mShadeLog.logMotionEvent(event, "onTouch: non-down action, motion was aborted");
-                return false;
-            }
-
-            // If dragging should not expand the notifications shade, then return false.
-            if (!mNotificationsDragEnabled) {
-                if (mTracking) {
-                    // Turn off tracking if it's on or the shade can get stuck in the down position.
-                    onTrackingStopped(true /* expand */);
+                if (mCommandQueue.panelsEnabled()
+                        && !mNotificationStackScrollLayoutController.isLongPressInProgress()
+                        && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
+                    mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
+                    mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
+                    return true;
                 }
-                mShadeLog.logMotionEvent(event, "onTouch: drag not enabled");
-                return false;
-            }
-
-            // On expanding, single mouse click expands the panel instead of dragging.
-            if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
-                if (event.getAction() == MotionEvent.ACTION_UP) {
-                    expand(true);
+                if (!shouldQuickSettingsIntercept(mDownX, mDownY, 0)
+                        && mPulseExpansionHandler.onInterceptTouchEvent(event)) {
+                    return true;
                 }
-                return true;
+
+                if (!isFullyCollapsed() && onQsIntercept(event)) {
+                    if (DEBUG_LOGCAT) Log.d(TAG, "onQsIntercept true");
+                    return true;
+                }
+                return super.onInterceptTouchEvent(event);
             }
 
-            /*
-             * We capture touch events here and update the expand height here in case according to
-             * the users fingers. This also handles multi-touch.
-             *
-             * Flinging is also enabled in order to open or close the shade.
-             */
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (event.getAction() == MotionEvent.ACTION_DOWN) {
+                    if (event.getDownTime() == mLastTouchDownTime) {
+                        // An issue can occur when swiping down after unlock, where multiple down
+                        // events are received in this handler with identical downTimes. Until the
+                        // source of the issue can be located, detect this case and ignore.
+                        // see b/193350347
+                        Log.w(TAG, "Duplicate down event detected... ignoring");
+                        return true;
+                    }
+                    mLastTouchDownTime = event.getDownTime();
+                }
 
-            int pointerIndex = event.findPointerIndex(mTrackingPointer);
-            if (pointerIndex < 0) {
-                pointerIndex = 0;
-                mTrackingPointer = event.getPointerId(pointerIndex);
+
+                if (mBlockTouches || (mQsFullyExpanded && mQs != null
+                        && mQs.disallowPanelTouches())) {
+                    return false;
+                }
+
+                // Do not allow panel expansion if bouncer is scrimmed or showing over a dream,
+                // otherwise user would be able to pull down QS or expand the shade.
+                if (mCentralSurfaces.isBouncerShowingScrimmed()
+                        || mCentralSurfaces.isBouncerShowingOverDream()) {
+                    return false;
+                }
+
+                // Make sure the next touch won't the blocked after the current ends.
+                if (event.getAction() == MotionEvent.ACTION_UP
+                        || event.getAction() == MotionEvent.ACTION_CANCEL) {
+                    mBlockingExpansionForCurrentTouch = false;
+                }
+                // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
+                // without any ACTION_MOVE event.
+                // In such case, simply expand the panel instead of being stuck at the bottom bar.
+                if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
+                    expand(true /* animate */);
+                }
+                initDownStates(event);
+
+                // If pulse is expanding already, let's give it the touch. There are situations
+                // where the panel starts expanding even though we're also pulsing
+                boolean pulseShouldGetTouch = (!mIsExpanding
+                        && !shouldQuickSettingsIntercept(mDownX, mDownY, 0))
+                        || mPulseExpansionHandler.isExpanding();
+                if (pulseShouldGetTouch && mPulseExpansionHandler.onTouchEvent(event)) {
+                    // We're expanding all the other ones shouldn't get this anymore
+                    mShadeLog.logMotionEvent(event, "onTouch: PulseExpansionHandler handled event");
+                    return true;
+                }
+                if (mListenForHeadsUp && !mHeadsUpTouchHelper.isTrackingHeadsUp()
+                        && !mNotificationStackScrollLayoutController.isLongPressInProgress()
+                        && mHeadsUpTouchHelper.onInterceptTouchEvent(event)) {
+                    mMetricsLogger.count(COUNTER_PANEL_OPEN_PEEK, 1);
+                }
+                boolean handled = mHeadsUpTouchHelper.onTouchEvent(event);
+
+                if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && handleQsTouch(event)) {
+                    mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event");
+                    return true;
+                }
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) {
+                    mMetricsLogger.count(COUNTER_PANEL_OPEN, 1);
+                    handled = true;
+                }
+
+                if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyExpanded()
+                        && mStatusBarKeyguardViewManager.isShowing()) {
+                    mStatusBarKeyguardViewManager.updateKeyguardPosition(event.getX());
+                }
+
+                handled |= super.onTouch(v, event);
+                return !mDozing || mPulsing || handled;
             }
-            final float x = event.getX(pointerIndex);
-            final float y = event.getY(pointerIndex);
-
-            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                mGestureWaitForTouchSlop = shouldGestureWaitForTouchSlop();
-                mIgnoreXTouchSlop = true;
-            }
-
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
-                    mMinExpandHeight = 0.0f;
-                    mPanelClosedOnDown = isFullyCollapsed();
-                    mHasLayoutedSinceDown = false;
-                    mUpdateFlingOnLayout = false;
-                    mMotionAborted = false;
-                    mDownTime = mSystemClock.uptimeMillis();
-                    mTouchAboveFalsingThreshold = false;
-                    mCollapsedAndHeadsUpOnDown =
-                            isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();
-                    addMovement(event);
-                    boolean regularHeightAnimationRunning = mHeightAnimator != null
-                            && !mHintAnimationRunning && !mIsSpringBackAnimation;
-                    if (!mGestureWaitForTouchSlop || regularHeightAnimationRunning) {
-                        mTouchSlopExceeded = regularHeightAnimationRunning
-                                || mTouchSlopExceededBeforeDown;
-                        cancelHeightAnimator();
-                        onTrackingStarted();
-                    }
-                    if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
-                            && !mCentralSurfaces.isBouncerShowing()) {
-                        startOpening(event);
-                    }
-                    break;
-
-                case MotionEvent.ACTION_POINTER_UP:
-                    final int upPointer = event.getPointerId(event.getActionIndex());
-                    if (mTrackingPointer == upPointer) {
-                        // gesture is ongoing, find a new pointer to track
-                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
-                        final float newY = event.getY(newIndex);
-                        final float newX = event.getX(newIndex);
-                        mTrackingPointer = event.getPointerId(newIndex);
-                        mHandlingPointerUp = true;
-                        startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight);
-                        mHandlingPointerUp = false;
-                    }
-                    break;
-                case MotionEvent.ACTION_POINTER_DOWN:
-                    if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
-                        mMotionAborted = true;
-                        endMotionEvent(event, x, y, true /* forceCancel */);
-                        return false;
-                    }
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    addMovement(event);
-                    float h = y - mInitialTouchY;
-
-                    // If the panel was collapsed when touching, we only need to check for the
-                    // y-component of the gesture, as we have no conflicting horizontal gesture.
-                    if (Math.abs(h) > getTouchSlop(event)
-                            && (Math.abs(h) > Math.abs(x - mInitialTouchX)
-                            || mIgnoreXTouchSlop)) {
-                        mTouchSlopExceeded = true;
-                        if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
-                            if (mInitialOffsetOnTouch != 0f) {
-                                startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
-                                h = 0;
-                            }
-                            cancelHeightAnimator();
-                            onTrackingStarted();
-                        }
-                    }
-                    float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
-                    newHeight = Math.max(newHeight, mMinExpandHeight);
-                    if (-h >= getFalsingThreshold()) {
-                        mTouchAboveFalsingThreshold = true;
-                        mUpwardsWhenThresholdReached = isDirectionUpwards(x, y);
-                    }
-                    if ((!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
-                        // Count h==0 as part of swipe-up,
-                        // otherwise {@link NotificationStackScrollLayout}
-                        // wrongly enables stack height updates at the start of lockscreen swipe-up
-                        mAmbientState.setSwipingUp(h <= 0);
-                        setExpandedHeightInternal(newHeight);
-                    }
-                    break;
-
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    addMovement(event);
-                    endMotionEvent(event, x, y, false /* forceCancel */);
-                    // mHeightAnimator is null, there is no remaining frame, ends instrumenting.
-                    if (mHeightAnimator == null) {
-                        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
-                            endJankMonitoring();
-                        } else {
-                            cancelJankMonitoring();
-                        }
-                    }
-                    break;
-            }
-            return !mGestureWaitForTouchSlop || mTracking;
-        }
+        };
     }
 
     private final PhoneStatusBarView.TouchEventHandler mStatusBarViewTouchEventHandler =
@@ -4854,7 +4280,8 @@
                 }
             };
 
-    private OnConfigurationChangedListener createOnConfigurationChangedListener() {
+    @Override
+    protected OnConfigurationChangedListener createOnConfigurationChangedListener() {
         return new OnConfigurationChangedListener();
     }
 
@@ -4916,585 +4343,6 @@
                 .commitUpdate(mDisplayId);
     }
 
-    private void logf(String fmt, Object... args) {
-        Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
-    }
-
-    private void notifyExpandingStarted() {
-        if (!mExpanding) {
-            mExpanding = true;
-            onExpandingStarted();
-        }
-    }
-
-    private void notifyExpandingFinished() {
-        endClosing();
-        if (mExpanding) {
-            mExpanding = false;
-            onExpandingFinished();
-        }
-    }
-
-    private float getTouchSlop(MotionEvent event) {
-        // Adjust the touch slop if another gesture may be being performed.
-        return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
-                ? mTouchSlop * mSlopMultiplier
-                : mTouchSlop;
-    }
-
-    private void addMovement(MotionEvent event) {
-        // Add movement to velocity tracker using raw screen X and Y coordinates instead
-        // of window coordinates because the window frame may be moving at the same time.
-        float deltaX = event.getRawX() - event.getX();
-        float deltaY = event.getRawY() - event.getY();
-        event.offsetLocation(deltaX, deltaY);
-        mVelocityTracker.addMovement(event);
-        event.offsetLocation(-deltaX, -deltaY);
-    }
-
-    public void startExpandLatencyTracking() {
-        if (mLatencyTracker.isEnabled()) {
-            mLatencyTracker.onActionStart(LatencyTracker.ACTION_EXPAND_PANEL);
-            mExpandLatencyTracking = true;
-        }
-    }
-
-    private void startOpening(MotionEvent event) {
-        updatePanelExpansionAndVisibility();
-        maybeVibrateOnOpening();
-
-        //TODO: keyguard opens QS a different way; log that too?
-
-        // Log the position of the swipe that opened the panel
-        float width = mCentralSurfaces.getDisplayWidth();
-        float height = mCentralSurfaces.getDisplayHeight();
-        int rot = mCentralSurfaces.getRotation();
-
-        mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND,
-                (int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot);
-        mLockscreenGestureLogger
-                .log(LockscreenUiEvent.LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND);
-    }
-
-    private void maybeVibrateOnOpening() {
-        if (mVibrateOnOpening) {
-            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
-        }
-    }
-
-    /**
-     * @return whether the swiping direction is upwards and above a 45 degree angle compared to the
-     * horizontal direction
-     */
-    private boolean isDirectionUpwards(float x, float y) {
-        float xDiff = x - mInitialExpandX;
-        float yDiff = y - mInitialExpandY;
-        if (yDiff >= 0) {
-            return false;
-        }
-        return Math.abs(yDiff) >= Math.abs(xDiff);
-    }
-
-    public void startExpandMotion(float newX, float newY, boolean startTracking,
-            float expandedHeight) {
-        if (!mHandlingPointerUp && !mStatusBarStateController.isDozing()) {
-            beginJankMonitoring();
-        }
-        mInitialOffsetOnTouch = expandedHeight;
-        mInitialExpandY = newY;
-        mInitialExpandX = newX;
-        mInitialTouchFromKeyguard = mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
-        if (startTracking) {
-            mTouchSlopExceeded = true;
-            setExpandedHeight(mInitialOffsetOnTouch);
-            onTrackingStarted();
-        }
-    }
-
-    private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
-        mTrackingPointer = -1;
-        mAmbientState.setSwipingUp(false);
-        if ((mTracking && mTouchSlopExceeded) || Math.abs(x - mInitialExpandX) > mTouchSlop
-                || Math.abs(y - mInitialExpandY) > mTouchSlop
-                || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
-            mVelocityTracker.computeCurrentVelocity(1000);
-            float vel = mVelocityTracker.getYVelocity();
-            float vectorVel = (float) Math.hypot(
-                    mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
-
-            final boolean onKeyguard =
-                    mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
-
-            final boolean expand;
-            if (mKeyguardStateController.isKeyguardFadingAway()
-                    || (mInitialTouchFromKeyguard && !onKeyguard)) {
-                // Don't expand for any touches that started from the keyguard and ended after the
-                // keyguard is gone.
-                expand = false;
-            } else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
-                if (onKeyguard) {
-                    expand = true;
-                } else if (mCentralSurfaces.isBouncerShowingOverDream()) {
-                    expand = false;
-                } else {
-                    // If we get a cancel, put the shade back to the state it was in when the
-                    // gesture started
-                    expand = !mPanelClosedOnDown;
-                }
-            } else {
-                expand = flingExpands(vel, vectorVel, x, y);
-            }
-
-            mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
-                    mCentralSurfaces.isFalsingThresholdNeeded(),
-                    mCentralSurfaces.isWakeUpComingFromTouch());
-            // Log collapse gesture if on lock screen.
-            if (!expand && onKeyguard) {
-                float displayDensity = mCentralSurfaces.getDisplayDensity();
-                int heightDp = (int) Math.abs((y - mInitialExpandY) / displayDensity);
-                int velocityDp = (int) Math.abs(vel / displayDensity);
-                mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
-                mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
-            }
-            @Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
-                    : y - mInitialExpandY > 0 ? QUICK_SETTINGS
-                            : (mKeyguardStateController.canDismissLockScreen()
-                                    ? UNLOCK : BOUNCER_UNLOCK);
-
-            fling(vel, expand, isFalseTouch(x, y, interactionType));
-            onTrackingStopped(expand);
-            mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
-            if (mUpdateFlingOnLayout) {
-                mUpdateFlingVelocity = vel;
-            }
-        } else if (!mCentralSurfaces.isBouncerShowing()
-                && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()
-                && !mKeyguardStateController.isKeyguardGoingAway()) {
-            boolean expands = onEmptySpaceClick();
-            onTrackingStopped(expands);
-        }
-        mVelocityTracker.clear();
-    }
-
-    private float getCurrentExpandVelocity() {
-        mVelocityTracker.computeCurrentVelocity(1000);
-        return mVelocityTracker.getYVelocity();
-    }
-
-    private void endClosing() {
-        if (mClosing) {
-            setIsClosing(false);
-            onClosingFinished();
-        }
-    }
-
-    /**
-     * @param x the final x-coordinate when the finger was lifted
-     * @param y the final y-coordinate when the finger was lifted
-     * @return whether this motion should be regarded as a false touch
-     */
-    private boolean isFalseTouch(float x, float y,
-            @Classifier.InteractionType int interactionType) {
-        if (!mCentralSurfaces.isFalsingThresholdNeeded()) {
-            return false;
-        }
-        if (mFalsingManager.isClassifierEnabled()) {
-            return mFalsingManager.isFalseTouch(interactionType);
-        }
-        if (!mTouchAboveFalsingThreshold) {
-            return true;
-        }
-        if (mUpwardsWhenThresholdReached) {
-            return false;
-        }
-        return !isDirectionUpwards(x, y);
-    }
-
-    private void fling(float vel, boolean expand, boolean expandBecauseOfFalsing) {
-        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, expandBecauseOfFalsing);
-    }
-
-    private void fling(float vel, boolean expand, float collapseSpeedUpFactor,
-            boolean expandBecauseOfFalsing) {
-        float target = expand ? getMaxPanelHeight() : 0;
-        if (!expand) {
-            setIsClosing(true);
-        }
-        flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
-    }
-
-    private void springBack() {
-        if (mOverExpansion == 0) {
-            onFlingEnd(false /* cancelled */);
-            return;
-        }
-        mIsSpringBackAnimation = true;
-        ValueAnimator animator = ValueAnimator.ofFloat(mOverExpansion, 0);
-        animator.addUpdateListener(
-                animation -> setOverExpansionInternal((float) animation.getAnimatedValue(),
-                        false /* isFromGesture */));
-        animator.setDuration(SHADE_OPEN_SPRING_BACK_DURATION);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        animator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mIsSpringBackAnimation = false;
-                onFlingEnd(mCancelled);
-            }
-        });
-        setAnimator(animator);
-        animator.start();
-    }
-
-    public String getName() {
-        return mViewName;
-    }
-
-    public void setExpandedHeight(float height) {
-        if (DEBUG) logf("setExpandedHeight(%.1f)", height);
-        setExpandedHeightInternal(height);
-    }
-
-    private void requestPanelHeightUpdate() {
-        float currentMaxPanelHeight = getMaxPanelHeight();
-
-        if (isFullyCollapsed()) {
-            return;
-        }
-
-        if (currentMaxPanelHeight == mExpandedHeight) {
-            return;
-        }
-
-        if (mTracking && !isTrackingBlocked()) {
-            return;
-        }
-
-        if (mHeightAnimator != null && !mIsSpringBackAnimation) {
-            mPanelUpdateWhenAnimatorEnds = true;
-            return;
-        }
-
-        setExpandedHeight(currentMaxPanelHeight);
-    }
-
-    public void setExpandedHeightInternal(float h) {
-        if (isNaN(h)) {
-            Log.wtf(TAG, "ExpandedHeight set to NaN");
-        }
-        mNotificationShadeWindowController.batchApplyWindowLayoutParams(() -> {
-            if (mExpandLatencyTracking && h != 0f) {
-                DejankUtils.postAfterTraversal(
-                        () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
-                mExpandLatencyTracking = false;
-            }
-            float maxPanelHeight = getMaxPanelHeight();
-            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;
-            }
-
-            // 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) {
-                mExpandedHeight = 0f;
-                if (mHeightAnimator != null) {
-                    mHeightAnimator.end();
-                }
-            }
-            mExpansionDragDownAmountPx = h;
-            mExpandedFraction = Math.min(1f,
-                    maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
-            mAmbientState.setExpansionFraction(mExpandedFraction);
-            onHeightUpdated(mExpandedHeight);
-            updatePanelExpansionAndVisibility();
-        });
-    }
-
-    /**
-     * Set the current overexpansion
-     *
-     * @param overExpansion the amount of overexpansion to apply
-     * @param isFromGesture is this amount from a gesture and needs to be rubberBanded?
-     */
-    private void setOverExpansionInternal(float overExpansion, boolean isFromGesture) {
-        if (!isFromGesture) {
-            mLastGesturedOverExpansion = -1;
-            setOverExpansion(overExpansion);
-        } else if (mLastGesturedOverExpansion != overExpansion) {
-            mLastGesturedOverExpansion = overExpansion;
-            final float heightForFullOvershoot = mView.getHeight() / 3.0f;
-            float newExpansion = MathUtils.saturate(overExpansion / heightForFullOvershoot);
-            newExpansion = Interpolators.getOvershootInterpolation(newExpansion);
-            setOverExpansion(newExpansion * mPanelFlingOvershootAmount * 2.0f);
-        }
-    }
-
-    public void setExpandedFraction(float frac) {
-        setExpandedHeight(getMaxPanelHeight() * frac);
-    }
-
-    public float getExpandedHeight() {
-        return mExpandedHeight;
-    }
-
-    public float getExpandedFraction() {
-        return mExpandedFraction;
-    }
-
-    public boolean isFullyExpanded() {
-        return mExpandedHeight >= getMaxPanelHeight();
-    }
-
-    public boolean isFullyCollapsed() {
-        return mExpandedFraction <= 0.0f;
-    }
-
-    public boolean isCollapsing() {
-        return mClosing || mIsLaunchAnimationRunning;
-    }
-
-    public boolean isFlinging() {
-        return mIsFlinging;
-    }
-
-    public boolean isTracking() {
-        return mTracking;
-    }
-
-    public boolean canPanelBeCollapsed() {
-        return !isFullyCollapsed() && !mTracking && !mClosing;
-    }
-
-    private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
-            mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
-
-    public void instantCollapse() {
-        abortAnimations();
-        setExpandedFraction(0f);
-        if (mExpanding) {
-            notifyExpandingFinished();
-        }
-        if (mInstantExpanding) {
-            mInstantExpanding = false;
-            updatePanelExpansionAndVisibility();
-        }
-    }
-
-    private void abortAnimations() {
-        cancelHeightAnimator();
-        mView.removeCallbacks(mFlingCollapseRunnable);
-    }
-
-    public boolean isUnlockHintRunning() {
-        return mHintAnimationRunning;
-    }
-
-    /**
-     * Phase 1: Move everything upwards.
-     */
-    private void startUnlockHintAnimationPhase1(final Runnable onAnimationFinished) {
-        float target = Math.max(0, getMaxPanelHeight() - mHintDistance);
-        ValueAnimator animator = createHeightAnimator(target);
-        animator.setDuration(250);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        animator.addListener(new AnimatorListenerAdapter() {
-            private boolean mCancelled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mCancelled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (mCancelled) {
-                    setAnimator(null);
-                    onAnimationFinished.run();
-                } else {
-                    startUnlockHintAnimationPhase2(onAnimationFinished);
-                }
-            }
-        });
-        animator.start();
-        setAnimator(animator);
-
-        final List<ViewPropertyAnimator> indicationAnimators =
-                mKeyguardBottomArea.getIndicationAreaAnimators();
-        for (final ViewPropertyAnimator indicationAreaAnimator : indicationAnimators) {
-            indicationAreaAnimator
-                    .translationY(-mHintDistance)
-                    .setDuration(250)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .withEndAction(() -> indicationAreaAnimator
-                            .translationY(0)
-                            .setDuration(450)
-                            .setInterpolator(mBounceInterpolator)
-                            .start())
-                    .start();
-        }
-    }
-
-    private void setAnimator(ValueAnimator animator) {
-        mHeightAnimator = animator;
-        if (animator == null && mPanelUpdateWhenAnimatorEnds) {
-            mPanelUpdateWhenAnimatorEnds = false;
-            requestPanelHeightUpdate();
-        }
-    }
-
-    /**
-     * Phase 2: Bounce down.
-     */
-    private void startUnlockHintAnimationPhase2(final Runnable onAnimationFinished) {
-        ValueAnimator animator = createHeightAnimator(getMaxPanelHeight());
-        animator.setDuration(450);
-        animator.setInterpolator(mBounceInterpolator);
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                setAnimator(null);
-                onAnimationFinished.run();
-                updatePanelExpansionAndVisibility();
-            }
-        });
-        animator.start();
-        setAnimator(animator);
-    }
-
-    private ValueAnimator createHeightAnimator(float targetHeight) {
-        return createHeightAnimator(targetHeight, 0.0f /* performOvershoot */);
-    }
-
-    /**
-     * Create an animator that can also overshoot
-     *
-     * @param targetHeight    the target height
-     * @param overshootAmount the amount of overshoot desired
-     */
-    private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) {
-        float startExpansion = mOverExpansion;
-        ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
-        animator.addUpdateListener(
-                animation -> {
-                    if (overshootAmount > 0.0f
-                            // Also remove the overExpansion when collapsing
-                            || (targetHeight == 0.0f && startExpansion != 0)) {
-                        final float expansion = MathUtils.lerp(
-                                startExpansion,
-                                mPanelFlingOvershootAmount * overshootAmount,
-                                Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
-                                        animator.getAnimatedFraction()));
-                        setOverExpansionInternal(expansion, false /* isFromGesture */);
-                    }
-                    setExpandedHeightInternal((float) animation.getAnimatedValue());
-                });
-        return animator;
-    }
-
-    /** Update the visibility of {@link PanelView} if necessary. */
-    public void updateVisibility() {
-        mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE);
-    }
-
-    /**
-     * Updates the panel expansion and {@link PanelView} visibility if necessary.
-     *
-     * TODO(b/200063118): Could public calls to this method be replaced with calls to
-     *   {@link #updateVisibility()}? That would allow us to make this method private.
-     */
-    public void updatePanelExpansionAndVisibility() {
-        mPanelExpansionStateManager.onPanelExpansionChanged(
-                mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
-        updateVisibility();
-    }
-
-    public boolean isExpanded() {
-        return mExpandedFraction > 0f
-                || mInstantExpanding
-                || isPanelVisibleBecauseOfHeadsUp()
-                || mTracking
-                || mHeightAnimator != null
-                && !mIsSpringBackAnimation;
-    }
-
-    /**
-     * Gets called when the user performs a click anywhere in the empty area of the panel.
-     *
-     * @return whether the panel will be expanded after the action performed by this method
-     */
-    private boolean onEmptySpaceClick() {
-        if (mHintAnimationRunning) {
-            return true;
-        }
-        return onMiddleClicked();
-    }
-
-    @VisibleForTesting
-    boolean isClosing() {
-        return mClosing;
-    }
-
-    public void collapseWithDuration(int animationDuration) {
-        mFixedDuration = animationDuration;
-        collapse(false /* delayed */, 1.0f /* speedUpFactor */);
-        mFixedDuration = NO_FIXED_DURATION;
-    }
-
-    public ViewGroup getView() {
-        // TODO: remove this method, or at least reduce references to it.
-        return mView;
-    }
-
-    private void beginJankMonitoring() {
-        if (mInteractionJankMonitor == null) {
-            return;
-        }
-        InteractionJankMonitor.Configuration.Builder builder =
-                InteractionJankMonitor.Configuration.Builder.withView(
-                                InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
-                                mView)
-                        .setTag(isFullyCollapsed() ? "Expand" : "Collapse");
-        mInteractionJankMonitor.begin(builder);
-    }
-
-    private void endJankMonitoring() {
-        if (mInteractionJankMonitor == null) {
-            return;
-        }
-        InteractionJankMonitor.getInstance().end(
-                InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
-    }
-
-    private void cancelJankMonitoring() {
-        if (mInteractionJankMonitor == null) {
-            return;
-        }
-        InteractionJankMonitor.getInstance().cancel(
-                InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
-    }
-
-    private float getExpansionFraction() {
-        return mExpandedFraction;
-    }
-
-    private PanelExpansionStateManager getPanelExpansionStateManager() {
-        return mPanelExpansionStateManager;
-    }
-
     private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
         @Override
         public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
@@ -5801,7 +4649,6 @@
         public void onDozeAmountChanged(float linearAmount, float amount) {
             mInterpolatedDarkAmount = amount;
             mLinearDarkAmount = linearAmount;
-            mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
             positionClockAndNotifications();
         }
     }
@@ -5856,7 +4703,6 @@
     public void showAodUi() {
         setDozing(true /* dozing */, false /* animate */);
         mStatusBarStateController.setUpcomingState(KEYGUARD);
-        mEntryManager.updateNotifications("showAodUi");
         mStatusBarStateListener.onStateChanged(KEYGUARD);
         mStatusBarStateListener.onDozeAmountChanged(1f, 1f);
         setExpandedFraction(1f);
@@ -5900,19 +4746,13 @@
         }
     }
 
-    private class OnLayoutChangeListener implements View.OnLayoutChangeListener {
+    private class OnLayoutChangeListenerImpl extends OnLayoutChangeListener {
 
         @Override
         public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
                 int oldTop, int oldRight, int oldBottom) {
             DejankUtils.startDetectingBlockingIpcs("NVP#onLayout");
-            requestPanelHeightUpdate();
-            mHasLayoutedSinceDown = true;
-            if (mUpdateFlingOnLayout) {
-                abortAnimations();
-                fling(mUpdateFlingVelocity, true /* expands */);
-                mUpdateFlingOnLayout = false;
-            }
+            super.onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom);
             updateMaxDisplayedNotifications(!shouldAvoidChangingNotificationsCount());
             setIsFullWidth(mNotificationStackScrollLayoutController.getWidth() == mView.getWidth());
 
@@ -6168,12 +5008,4 @@
             }
         }
     }
-
-    public class OnConfigurationChangedListener implements
-            PanelView.OnConfigurationChangedListener {
-        @Override
-        public void onConfigurationChanged(Configuration newConfig) {
-            loadDimens();
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index fec76b6..abafecc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -29,12 +29,12 @@
 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;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -51,7 +51,6 @@
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 
 import java.io.PrintWriter;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -88,7 +87,6 @@
     private final DockManager mDockManager;
     private final NotificationPanelViewController mNotificationPanelViewController;
     private final PanelExpansionStateManager mPanelExpansionStateManager;
-    private final Optional<LowLightClockController> mLowLightClockController;
 
     private boolean mIsTrackingBarGesture = false;
 
@@ -106,7 +104,6 @@
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             StatusBarWindowStateController statusBarWindowStateController,
             LockIconViewController lockIconViewController,
-            Optional<LowLightClockController> lowLightClockController,
             CentralSurfaces centralSurfaces,
             NotificationShadeWindowController controller,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -125,7 +122,6 @@
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mStatusBarWindowStateController = statusBarWindowStateController;
         mLockIconViewController = lockIconViewController;
-        mLowLightClockController = lowLightClockController;
         mService = centralSurfaces;
         mNotificationShadeWindowController = controller;
         mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
@@ -143,13 +139,18 @@
         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);
         mGestureDetector = new GestureDetector(mView.getContext(), mPulsingGestureListener);
 
-        mLowLightClockController.ifPresent(controller -> controller.attachLowLightClockView(mView));
-
         mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
             @Override
             public Boolean handleDispatchTouchEvent(MotionEvent ev) {
@@ -434,21 +435,6 @@
         mStatusBarViewController = statusBarViewController;
     }
 
-    /**
-     * Tell the controller that dozing has begun or ended.
-     * @param dozing True if dozing has begun.
-     */
-    public void setDozing(boolean dozing) {
-        mLowLightClockController.ifPresent(controller -> controller.showLowLightClock(dozing));
-    }
-
-    /**
-     * Tell the controller to perform burn-in prevention.
-     */
-    public void dozeTimeTick() {
-        mLowLightClockController.ifPresent(LowLightClockController::dozeTimeTick);
-    }
-
     @VisibleForTesting
     void setDragDownHelper(DragDownHelper dragDownHelper) {
         mDragDownHelper = dragDownHelper;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PanelView.java b/packages/SystemUI/src/com/android/systemui/shade/PanelView.java
deleted file mode 100644
index 4349d81..0000000
--- a/packages/SystemUI/src/com/android/systemui/shade/PanelView.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shade;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.widget.FrameLayout;
-
-import com.android.systemui.statusbar.phone.CentralSurfaces;
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
-import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
-
-public abstract class PanelView extends FrameLayout {
-    public static final boolean DEBUG = false;
-    public static final String TAG = PanelView.class.getSimpleName();
-    private NotificationPanelViewController.TouchHandler mTouchHandler;
-
-    protected CentralSurfaces mCentralSurfaces;
-    protected HeadsUpManagerPhone mHeadsUpManager;
-
-    protected KeyguardBottomAreaView mKeyguardBottomArea;
-    private OnConfigurationChangedListener mOnConfigurationChangedListener;
-
-    public PanelView(Context context) {
-        super(context);
-    }
-
-    public PanelView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public PanelView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    public void setOnTouchListener(NotificationPanelViewController.TouchHandler touchHandler) {
-        super.setOnTouchListener(touchHandler);
-        mTouchHandler = touchHandler;
-    }
-
-    public void setOnConfigurationChangedListener(OnConfigurationChangedListener listener) {
-        mOnConfigurationChangedListener = listener;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        return mTouchHandler.onInterceptTouchEvent(event);
-    }
-
-    @Override
-    public void dispatchConfigurationChanged(Configuration newConfig) {
-        super.dispatchConfigurationChanged(newConfig);
-        mOnConfigurationChangedListener.onConfigurationChanged(newConfig);
-    }
-
-    interface OnConfigurationChangedListener {
-        void onConfigurationChanged(Configuration newConfig);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
new file mode 100644
index 0000000..a0076937
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/PanelViewController.java
@@ -0,0 +1,1477 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade;
+
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
+import static com.android.systemui.classifier.Classifier.GENERIC;
+import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+import static com.android.systemui.classifier.Classifier.UNLOCK;
+import static com.android.systemui.shade.NotificationPanelView.DEBUG;
+
+import static java.lang.Float.isNaN;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.VibrationEffect;
+import android.util.Log;
+import android.util.MathUtils;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
+
+import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.LatencyTracker;
+import com.android.systemui.DejankUtils;
+import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
+import com.android.systemui.classifier.Classifier;
+import com.android.systemui.doze.DozeLog;
+import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.notification.stack.AmbientState;
+import com.android.systemui.statusbar.phone.BounceInterpolator;
+import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
+import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.time.SystemClock;
+import com.android.wm.shell.animation.FlingAnimationUtils;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+public abstract class PanelViewController {
+    public static final String TAG = NotificationPanelView.class.getSimpleName();
+    public static final float FLING_MAX_LENGTH_SECONDS = 0.6f;
+    public static final float FLING_SPEED_UP_FACTOR = 0.6f;
+    public static final float FLING_CLOSING_MAX_LENGTH_SECONDS = 0.6f;
+    public static final float FLING_CLOSING_SPEED_UP_FACTOR = 0.6f;
+    private static final int NO_FIXED_DURATION = -1;
+    private static final long SHADE_OPEN_SPRING_OUT_DURATION = 350L;
+    private static final long SHADE_OPEN_SPRING_BACK_DURATION = 400L;
+
+    /**
+     * The factor of the usual high velocity that is needed in order to reach the maximum overshoot
+     * when flinging. A low value will make it that most flings will reach the maximum overshoot.
+     */
+    private static final float FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT = 0.5f;
+
+    protected long mDownTime;
+    protected boolean mTouchSlopExceededBeforeDown;
+    private float mMinExpandHeight;
+    private boolean mPanelUpdateWhenAnimatorEnds;
+    private final boolean mVibrateOnOpening;
+    protected boolean mIsLaunchAnimationRunning;
+    private int mFixedDuration = NO_FIXED_DURATION;
+    protected float mOverExpansion;
+
+    /**
+     * The overshoot amount when the panel flings open
+     */
+    private float mPanelFlingOvershootAmount;
+
+    /**
+     * The amount of pixels that we have overexpanded the last time with a gesture
+     */
+    private float mLastGesturedOverExpansion = -1;
+
+    /**
+     * Is the current animator the spring back animation?
+     */
+    private boolean mIsSpringBackAnimation;
+
+    private boolean mInSplitShade;
+
+    private void logf(String fmt, Object... args) {
+        Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args));
+    }
+
+    protected CentralSurfaces mCentralSurfaces;
+    protected HeadsUpManagerPhone mHeadsUpManager;
+    protected final StatusBarTouchableRegionManager mStatusBarTouchableRegionManager;
+
+    private float mHintDistance;
+    private float mInitialOffsetOnTouch;
+    private boolean mCollapsedAndHeadsUpOnDown;
+    private float mExpandedFraction = 0;
+    private float mExpansionDragDownAmountPx = 0;
+    protected float mExpandedHeight = 0;
+    private boolean mPanelClosedOnDown;
+    private boolean mHasLayoutedSinceDown;
+    private float mUpdateFlingVelocity;
+    private boolean mUpdateFlingOnLayout;
+    private boolean mClosing;
+    protected boolean mTracking;
+    private boolean mTouchSlopExceeded;
+    private int mTrackingPointer;
+    private int mTouchSlop;
+    private float mSlopMultiplier;
+    protected boolean mHintAnimationRunning;
+    private boolean mTouchAboveFalsingThreshold;
+    private boolean mTouchStartedInEmptyArea;
+    private boolean mMotionAborted;
+    private boolean mUpwardsWhenThresholdReached;
+    private boolean mAnimatingOnDown;
+    private boolean mHandlingPointerUp;
+
+    private ValueAnimator mHeightAnimator;
+    private final VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+    private final FlingAnimationUtils mFlingAnimationUtils;
+    private final FlingAnimationUtils mFlingAnimationUtilsClosing;
+    private final FlingAnimationUtils mFlingAnimationUtilsDismissing;
+    private final LatencyTracker mLatencyTracker;
+    private final FalsingManager mFalsingManager;
+    private final DozeLog mDozeLog;
+    private final VibratorHelper mVibratorHelper;
+
+    /**
+     * Whether an instant expand request is currently pending and we are just waiting for layout.
+     */
+    private boolean mInstantExpanding;
+    private boolean mAnimateAfterExpanding;
+    private boolean mIsFlinging;
+
+    private String mViewName;
+    private float mInitialExpandY;
+    private float mInitialExpandX;
+    private boolean mTouchDisabled;
+    private boolean mInitialTouchFromKeyguard;
+
+    /**
+     * Whether or not the NotificationPanelView can be expanded or collapsed with a drag.
+     */
+    private final boolean mNotificationsDragEnabled;
+
+    private final Interpolator mBounceInterpolator;
+    protected KeyguardBottomAreaView mKeyguardBottomArea;
+
+    /**
+     * Speed-up factor to be used when {@link #mFlingCollapseRunnable} runs the next time.
+     */
+    private float mNextCollapseSpeedUpFactor = 1.0f;
+
+    protected boolean mExpanding;
+    private boolean mGestureWaitForTouchSlop;
+    private boolean mIgnoreXTouchSlop;
+    private boolean mExpandLatencyTracking;
+    private final NotificationPanelView mView;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private final NotificationShadeWindowController mNotificationShadeWindowController;
+    protected final Resources mResources;
+    protected final KeyguardStateController mKeyguardStateController;
+    protected final SysuiStatusBarStateController mStatusBarStateController;
+    protected final AmbientState mAmbientState;
+    protected final LockscreenGestureLogger mLockscreenGestureLogger;
+    private final PanelExpansionStateManager mPanelExpansionStateManager;
+    private final InteractionJankMonitor mInteractionJankMonitor;
+    protected final SystemClock mSystemClock;
+
+    protected final ShadeLogger mShadeLog;
+
+    protected abstract void onExpandingFinished();
+
+    protected void onExpandingStarted() {
+    }
+
+    protected void notifyExpandingStarted() {
+        if (!mExpanding) {
+            mExpanding = true;
+            onExpandingStarted();
+        }
+    }
+
+    protected final void notifyExpandingFinished() {
+        endClosing();
+        if (mExpanding) {
+            mExpanding = false;
+            onExpandingFinished();
+        }
+    }
+
+    protected AmbientState getAmbientState() {
+        return mAmbientState;
+    }
+
+    public PanelViewController(
+            NotificationPanelView view,
+            FalsingManager falsingManager,
+            DozeLog dozeLog,
+            KeyguardStateController keyguardStateController,
+            SysuiStatusBarStateController statusBarStateController,
+            NotificationShadeWindowController notificationShadeWindowController,
+            VibratorHelper vibratorHelper,
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            LatencyTracker latencyTracker,
+            FlingAnimationUtils.Builder flingAnimationUtilsBuilder,
+            StatusBarTouchableRegionManager statusBarTouchableRegionManager,
+            LockscreenGestureLogger lockscreenGestureLogger,
+            PanelExpansionStateManager panelExpansionStateManager,
+            AmbientState ambientState,
+            InteractionJankMonitor interactionJankMonitor,
+            ShadeLogger shadeLogger,
+            SystemClock systemClock) {
+        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
+            @Override
+            public void onKeyguardFadingAwayChanged() {
+                requestPanelHeightUpdate();
+            }
+        });
+        mAmbientState = ambientState;
+        mView = view;
+        mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mLockscreenGestureLogger = lockscreenGestureLogger;
+        mPanelExpansionStateManager = panelExpansionStateManager;
+        mShadeLog = shadeLogger;
+        TouchHandler touchHandler = createTouchHandler();
+        mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+            @Override
+            public void onViewAttachedToWindow(View v) {
+                mViewName = mResources.getResourceName(mView.getId());
+            }
+
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+            }
+        });
+
+        mView.addOnLayoutChangeListener(createLayoutChangeListener());
+        mView.setOnTouchListener(touchHandler);
+        mView.setOnConfigurationChangedListener(createOnConfigurationChangedListener());
+
+        mResources = mView.getResources();
+        mKeyguardStateController = keyguardStateController;
+        mStatusBarStateController = statusBarStateController;
+        mNotificationShadeWindowController = notificationShadeWindowController;
+        mFlingAnimationUtils = flingAnimationUtilsBuilder
+                .reset()
+                .setMaxLengthSeconds(FLING_MAX_LENGTH_SECONDS)
+                .setSpeedUpFactor(FLING_SPEED_UP_FACTOR)
+                .build();
+        mFlingAnimationUtilsClosing = flingAnimationUtilsBuilder
+                .reset()
+                .setMaxLengthSeconds(FLING_CLOSING_MAX_LENGTH_SECONDS)
+                .setSpeedUpFactor(FLING_CLOSING_SPEED_UP_FACTOR)
+                .build();
+        mFlingAnimationUtilsDismissing = flingAnimationUtilsBuilder
+                .reset()
+                .setMaxLengthSeconds(0.5f)
+                .setSpeedUpFactor(0.6f)
+                .setX2(0.6f)
+                .setY2(0.84f)
+                .build();
+        mLatencyTracker = latencyTracker;
+        mBounceInterpolator = new BounceInterpolator();
+        mFalsingManager = falsingManager;
+        mDozeLog = dozeLog;
+        mNotificationsDragEnabled = mResources.getBoolean(
+                R.bool.config_enableNotificationShadeDrag);
+        mVibratorHelper = vibratorHelper;
+        mVibrateOnOpening = mResources.getBoolean(R.bool.config_vibrateOnIconAnimation);
+        mStatusBarTouchableRegionManager = statusBarTouchableRegionManager;
+        mInteractionJankMonitor = interactionJankMonitor;
+        mSystemClock = systemClock;
+    }
+
+    protected void loadDimens() {
+        final ViewConfiguration configuration = ViewConfiguration.get(mView.getContext());
+        mTouchSlop = configuration.getScaledTouchSlop();
+        mSlopMultiplier = configuration.getScaledAmbiguousGestureMultiplier();
+        mHintDistance = mResources.getDimension(R.dimen.hint_move_distance);
+        mPanelFlingOvershootAmount = mResources.getDimension(R.dimen.panel_overshoot_amount);
+        mInSplitShade = mResources.getBoolean(R.bool.config_use_split_notification_shade);
+    }
+
+    protected float getTouchSlop(MotionEvent event) {
+        // Adjust the touch slop if another gesture may be being performed.
+        return event.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE
+                ? mTouchSlop * mSlopMultiplier
+                : mTouchSlop;
+    }
+
+    private void addMovement(MotionEvent event) {
+        // Add movement to velocity tracker using raw screen X and Y coordinates instead
+        // of window coordinates because the window frame may be moving at the same time.
+        float deltaX = event.getRawX() - event.getX();
+        float deltaY = event.getRawY() - event.getY();
+        event.offsetLocation(deltaX, deltaY);
+        mVelocityTracker.addMovement(event);
+        event.offsetLocation(-deltaX, -deltaY);
+    }
+
+    public void setTouchAndAnimationDisabled(boolean disabled) {
+        mTouchDisabled = disabled;
+        if (mTouchDisabled) {
+            cancelHeightAnimator();
+            if (mTracking) {
+                onTrackingStopped(true /* expanded */);
+            }
+            notifyExpandingFinished();
+        }
+    }
+
+    public void startExpandLatencyTracking() {
+        if (mLatencyTracker.isEnabled()) {
+            mLatencyTracker.onActionStart(LatencyTracker.ACTION_EXPAND_PANEL);
+            mExpandLatencyTracking = true;
+        }
+    }
+
+    private void startOpening(MotionEvent event) {
+        updatePanelExpansionAndVisibility();
+        maybeVibrateOnOpening();
+
+        //TODO: keyguard opens QS a different way; log that too?
+
+        // Log the position of the swipe that opened the panel
+        float width = mCentralSurfaces.getDisplayWidth();
+        float height = mCentralSurfaces.getDisplayHeight();
+        int rot = mCentralSurfaces.getRotation();
+
+        mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND,
+                (int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot);
+        mLockscreenGestureLogger
+                .log(LockscreenUiEvent.LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND);
+    }
+
+    protected void maybeVibrateOnOpening() {
+        if (mVibrateOnOpening) {
+            mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
+        }
+    }
+
+    protected abstract float getOpeningHeight();
+
+    /**
+     * @return whether the swiping direction is upwards and above a 45 degree angle compared to the
+     * horizontal direction
+     */
+    private boolean isDirectionUpwards(float x, float y) {
+        float xDiff = x - mInitialExpandX;
+        float yDiff = y - mInitialExpandY;
+        if (yDiff >= 0) {
+            return false;
+        }
+        return Math.abs(yDiff) >= Math.abs(xDiff);
+    }
+
+    public void startExpandMotion(float newX, float newY, boolean startTracking,
+            float expandedHeight) {
+        if (!mHandlingPointerUp && !mStatusBarStateController.isDozing()) {
+            beginJankMonitoring();
+        }
+        mInitialOffsetOnTouch = expandedHeight;
+        mInitialExpandY = newY;
+        mInitialExpandX = newX;
+        mInitialTouchFromKeyguard = mKeyguardStateController.isShowing();
+        if (startTracking) {
+            mTouchSlopExceeded = true;
+            setExpandedHeight(mInitialOffsetOnTouch);
+            onTrackingStarted();
+        }
+    }
+
+    private void endMotionEvent(MotionEvent event, float x, float y, boolean forceCancel) {
+        mTrackingPointer = -1;
+        mAmbientState.setSwipingUp(false);
+        if ((mTracking && mTouchSlopExceeded) || Math.abs(x - mInitialExpandX) > mTouchSlop
+                || Math.abs(y - mInitialExpandY) > mTouchSlop
+                || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
+            mVelocityTracker.computeCurrentVelocity(1000);
+            float vel = mVelocityTracker.getYVelocity();
+            float vectorVel = (float) Math.hypot(
+                    mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity());
+
+            final boolean onKeyguard = mKeyguardStateController.isShowing();
+            final boolean expand;
+            if (mKeyguardStateController.isKeyguardFadingAway()
+                    || (mInitialTouchFromKeyguard && !onKeyguard)) {
+                // Don't expand for any touches that started from the keyguard and ended after the
+                // keyguard is gone.
+                expand = false;
+            } else if (event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) {
+                if (onKeyguard) {
+                    expand = true;
+                } else if (mCentralSurfaces.isBouncerShowingOverDream()) {
+                    expand = false;
+                } else {
+                    // If we get a cancel, put the shade back to the state it was in when the
+                    // gesture started
+                    expand = !mPanelClosedOnDown;
+                }
+            } else {
+                expand = flingExpands(vel, vectorVel, x, y);
+            }
+
+            mDozeLog.traceFling(expand, mTouchAboveFalsingThreshold,
+                    mCentralSurfaces.isFalsingThresholdNeeded(),
+                    mCentralSurfaces.isWakeUpComingFromTouch());
+            // Log collapse gesture if on lock screen.
+            if (!expand && onKeyguard) {
+                float displayDensity = mCentralSurfaces.getDisplayDensity();
+                int heightDp = (int) Math.abs((y - mInitialExpandY) / displayDensity);
+                int velocityDp = (int) Math.abs(vel / displayDensity);
+                mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp);
+                mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK);
+            }
+            @Classifier.InteractionType int interactionType = vel == 0 ? GENERIC
+                    : y - mInitialExpandY > 0 ? QUICK_SETTINGS
+                            : (mKeyguardStateController.canDismissLockScreen()
+                                    ? UNLOCK : BOUNCER_UNLOCK);
+
+            fling(vel, expand, isFalseTouch(x, y, interactionType));
+            onTrackingStopped(expand);
+            mUpdateFlingOnLayout = expand && mPanelClosedOnDown && !mHasLayoutedSinceDown;
+            if (mUpdateFlingOnLayout) {
+                mUpdateFlingVelocity = vel;
+            }
+        } else if (!mCentralSurfaces.isBouncerShowing()
+                && !mStatusBarKeyguardViewManager.isShowingAlternateAuthOrAnimating()
+                && !mKeyguardStateController.isKeyguardGoingAway()) {
+            boolean expands = onEmptySpaceClick();
+            onTrackingStopped(expands);
+        }
+        mVelocityTracker.clear();
+    }
+
+    protected float getCurrentExpandVelocity() {
+        mVelocityTracker.computeCurrentVelocity(1000);
+        return mVelocityTracker.getYVelocity();
+    }
+
+    protected abstract int getFalsingThreshold();
+
+    protected abstract boolean shouldGestureWaitForTouchSlop();
+
+    protected void onTrackingStopped(boolean expand) {
+        mTracking = false;
+        mCentralSurfaces.onTrackingStopped(expand);
+        updatePanelExpansionAndVisibility();
+    }
+
+    protected void onTrackingStarted() {
+        endClosing();
+        mTracking = true;
+        mCentralSurfaces.onTrackingStarted();
+        notifyExpandingStarted();
+        updatePanelExpansionAndVisibility();
+    }
+
+    /**
+     * @return Whether a pair of coordinates are inside the visible view content bounds.
+     */
+    protected abstract boolean isInContentBounds(float x, float y);
+
+    protected void cancelHeightAnimator() {
+        if (mHeightAnimator != null) {
+            if (mHeightAnimator.isRunning()) {
+                mPanelUpdateWhenAnimatorEnds = false;
+            }
+            mHeightAnimator.cancel();
+        }
+        endClosing();
+    }
+
+    private void endClosing() {
+        if (mClosing) {
+            setIsClosing(false);
+            onClosingFinished();
+        }
+    }
+
+    protected abstract boolean canCollapsePanelOnTouch();
+
+    protected float getContentHeight() {
+        return mExpandedHeight;
+    }
+
+    /**
+     * @param vel       the current vertical velocity of the motion
+     * @param vectorVel the length of the vectorial velocity
+     * @return whether a fling should expands the panel; contracts otherwise
+     */
+    protected boolean flingExpands(float vel, float vectorVel, float x, float y) {
+        if (mFalsingManager.isUnlockingDisabled()) {
+            return true;
+        }
+
+        @Classifier.InteractionType int interactionType = y - mInitialExpandY > 0
+                ? QUICK_SETTINGS : (
+                        mKeyguardStateController.canDismissLockScreen() ? UNLOCK : BOUNCER_UNLOCK);
+
+        if (isFalseTouch(x, y, interactionType)) {
+            return true;
+        }
+        if (Math.abs(vectorVel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
+            return shouldExpandWhenNotFlinging();
+        } else {
+            return vel > 0;
+        }
+    }
+
+    protected boolean shouldExpandWhenNotFlinging() {
+        return getExpandedFraction() > 0.5f;
+    }
+
+    /**
+     * @param x the final x-coordinate when the finger was lifted
+     * @param y the final y-coordinate when the finger was lifted
+     * @return whether this motion should be regarded as a false touch
+     */
+    private boolean isFalseTouch(float x, float y,
+            @Classifier.InteractionType int interactionType) {
+        if (!mCentralSurfaces.isFalsingThresholdNeeded()) {
+            return false;
+        }
+        if (mFalsingManager.isClassifierEnabled()) {
+            return mFalsingManager.isFalseTouch(interactionType);
+        }
+        if (!mTouchAboveFalsingThreshold) {
+            return true;
+        }
+        if (mUpwardsWhenThresholdReached) {
+            return false;
+        }
+        return !isDirectionUpwards(x, y);
+    }
+
+    protected void fling(float vel, boolean expand) {
+        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, false);
+    }
+
+    protected void fling(float vel, boolean expand, boolean expandBecauseOfFalsing) {
+        fling(vel, expand, 1.0f /* collapseSpeedUpFactor */, expandBecauseOfFalsing);
+    }
+
+    protected void fling(float vel, boolean expand, float collapseSpeedUpFactor,
+            boolean expandBecauseOfFalsing) {
+        float target = expand ? getMaxPanelHeight() : 0;
+        if (!expand) {
+            setIsClosing(true);
+        }
+        flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing);
+    }
+
+    protected void flingToHeight(float vel, boolean expand, float target,
+            float collapseSpeedUpFactor, boolean expandBecauseOfFalsing) {
+        if (target == mExpandedHeight && mOverExpansion == 0.0f) {
+            // We're at the target and didn't fling and there's no overshoot
+            onFlingEnd(false /* cancelled */);
+            return;
+        }
+        mIsFlinging = true;
+        // we want to perform an overshoot animation when flinging open
+        final boolean addOverscroll =
+                expand
+                        && !mInSplitShade // Split shade has its own overscroll logic
+                        && mStatusBarStateController.getState() != StatusBarState.KEYGUARD
+                        && mOverExpansion == 0.0f
+                        && vel >= 0;
+        final boolean shouldSpringBack = addOverscroll || (mOverExpansion != 0.0f && expand);
+        float overshootAmount = 0.0f;
+        if (addOverscroll) {
+            // Let's overshoot depending on the amount of velocity
+            overshootAmount = MathUtils.lerp(
+                    0.2f,
+                    1.0f,
+                    MathUtils.saturate(vel
+                            / (mFlingAnimationUtils.getHighVelocityPxPerSecond()
+                                    * FACTOR_OF_HIGH_VELOCITY_FOR_MAX_OVERSHOOT)));
+            overshootAmount += mOverExpansion / mPanelFlingOvershootAmount;
+        }
+        ValueAnimator animator = createHeightAnimator(target, overshootAmount);
+        if (expand) {
+            if (expandBecauseOfFalsing && vel < 0) {
+                vel = 0;
+            }
+            mFlingAnimationUtils.apply(animator, mExpandedHeight,
+                    target + overshootAmount * mPanelFlingOvershootAmount, vel, mView.getHeight());
+            if (vel == 0) {
+                animator.setDuration(SHADE_OPEN_SPRING_OUT_DURATION);
+            }
+        } else {
+            if (shouldUseDismissingAnimation()) {
+                if (vel == 0) {
+                    animator.setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED);
+                    long duration = (long) (200 + mExpandedHeight / mView.getHeight() * 100);
+                    animator.setDuration(duration);
+                } else {
+                    mFlingAnimationUtilsDismissing.apply(animator, mExpandedHeight, target, vel,
+                            mView.getHeight());
+                }
+            } else {
+                mFlingAnimationUtilsClosing.apply(
+                        animator, mExpandedHeight, target, vel, mView.getHeight());
+            }
+
+            // Make it shorter if we run a canned animation
+            if (vel == 0) {
+                animator.setDuration((long) (animator.getDuration() / collapseSpeedUpFactor));
+            }
+            if (mFixedDuration != NO_FIXED_DURATION) {
+                animator.setDuration(mFixedDuration);
+            }
+        }
+        animator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCancelled;
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                if (!mStatusBarStateController.isDozing()) {
+                    beginJankMonitoring();
+                }
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (shouldSpringBack && !mCancelled) {
+                    // After the shade is flinged open to an overscrolled state, spring back
+                    // the shade by reducing section padding to 0.
+                    springBack();
+                } else {
+                    onFlingEnd(mCancelled);
+                }
+            }
+        });
+        setAnimator(animator);
+        animator.start();
+    }
+
+    private void springBack() {
+        if (mOverExpansion == 0) {
+            onFlingEnd(false /* cancelled */);
+            return;
+        }
+        mIsSpringBackAnimation = true;
+        ValueAnimator animator = ValueAnimator.ofFloat(mOverExpansion, 0);
+        animator.addUpdateListener(
+                animation -> setOverExpansionInternal((float) animation.getAnimatedValue(),
+                        false /* isFromGesture */));
+        animator.setDuration(SHADE_OPEN_SPRING_BACK_DURATION);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        animator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCancelled;
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mIsSpringBackAnimation = false;
+                onFlingEnd(mCancelled);
+            }
+        });
+        setAnimator(animator);
+        animator.start();
+    }
+
+    protected void onFlingEnd(boolean cancelled) {
+        mIsFlinging = false;
+        // No overshoot when the animation ends
+        setOverExpansionInternal(0, false /* isFromGesture */);
+        setAnimator(null);
+        mKeyguardStateController.notifyPanelFlingEnd();
+        if (!cancelled) {
+            endJankMonitoring();
+            notifyExpandingFinished();
+        } else {
+            cancelJankMonitoring();
+        }
+        updatePanelExpansionAndVisibility();
+    }
+
+    protected abstract boolean shouldUseDismissingAnimation();
+
+    public String getName() {
+        return mViewName;
+    }
+
+    public void setExpandedHeight(float height) {
+        if (DEBUG) logf("setExpandedHeight(%.1f)", height);
+        setExpandedHeightInternal(height);
+    }
+
+    protected void requestPanelHeightUpdate() {
+        float currentMaxPanelHeight = getMaxPanelHeight();
+
+        if (isFullyCollapsed()) {
+            return;
+        }
+
+        if (currentMaxPanelHeight == mExpandedHeight) {
+            return;
+        }
+
+        if (mTracking && !isTrackingBlocked()) {
+            return;
+        }
+
+        if (mHeightAnimator != null && !mIsSpringBackAnimation) {
+            mPanelUpdateWhenAnimatorEnds = true;
+            return;
+        }
+
+        setExpandedHeight(currentMaxPanelHeight);
+    }
+
+    public void setExpandedHeightInternal(float h) {
+        if (isNaN(h)) {
+            Log.wtf(TAG, "ExpandedHeight set to NaN");
+        }
+        mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
+            if (mExpandLatencyTracking && h != 0f) {
+                DejankUtils.postAfterTraversal(
+                        () -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
+                mExpandLatencyTracking = false;
+            }
+            float maxPanelHeight = getMaxPanelHeight();
+            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;
+            }
+
+            // 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) {
+                mExpandedHeight = 0f;
+                if (mHeightAnimator != null) {
+                    mHeightAnimator.end();
+                }
+            }
+            mExpansionDragDownAmountPx = h;
+            mExpandedFraction = Math.min(1f,
+                    maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+            mAmbientState.setExpansionFraction(mExpandedFraction);
+            onHeightUpdated(mExpandedHeight);
+            updatePanelExpansionAndVisibility();
+        });
+    }
+
+    /**
+     * @return true if the panel tracking should be temporarily blocked; this is used when a
+     * conflicting gesture (opening QS) is happening
+     */
+    protected abstract boolean isTrackingBlocked();
+
+    protected void setOverExpansion(float overExpansion) {
+        mOverExpansion = overExpansion;
+    }
+
+    /**
+     * Set the current overexpansion
+     *
+     * @param overExpansion the amount of overexpansion to apply
+     * @param isFromGesture is this amount from a gesture and needs to be rubberBanded?
+     */
+    private void setOverExpansionInternal(float overExpansion, boolean isFromGesture) {
+        if (!isFromGesture) {
+            mLastGesturedOverExpansion = -1;
+            setOverExpansion(overExpansion);
+        } else if (mLastGesturedOverExpansion != overExpansion) {
+            mLastGesturedOverExpansion = overExpansion;
+            final float heightForFullOvershoot = mView.getHeight() / 3.0f;
+            float newExpansion = MathUtils.saturate(overExpansion / heightForFullOvershoot);
+            newExpansion = Interpolators.getOvershootInterpolation(newExpansion);
+            setOverExpansion(newExpansion * mPanelFlingOvershootAmount * 2.0f);
+        }
+    }
+
+    protected abstract void onHeightUpdated(float expandedHeight);
+
+    /**
+     * This returns the maximum height of the panel. Children should override this if their
+     * desired height is not the full height.
+     *
+     * @return the default implementation simply returns the maximum height.
+     */
+    protected abstract int getMaxPanelHeight();
+
+    public void setExpandedFraction(float frac) {
+        setExpandedHeight(getMaxPanelHeight() * frac);
+    }
+
+    public float getExpandedHeight() {
+        return mExpandedHeight;
+    }
+
+    public float getExpandedFraction() {
+        return mExpandedFraction;
+    }
+
+    public boolean isFullyExpanded() {
+        return mExpandedHeight >= getMaxPanelHeight();
+    }
+
+    public boolean isFullyCollapsed() {
+        return mExpandedFraction <= 0.0f;
+    }
+
+    public boolean isCollapsing() {
+        return mClosing || mIsLaunchAnimationRunning;
+    }
+
+    public boolean isFlinging() {
+        return mIsFlinging;
+    }
+
+    public boolean isTracking() {
+        return mTracking;
+    }
+
+    public void collapse(boolean delayed, float speedUpFactor) {
+        if (DEBUG) logf("collapse: " + this);
+        if (canPanelBeCollapsed()) {
+            cancelHeightAnimator();
+            notifyExpandingStarted();
+
+            // Set after notifyExpandingStarted, as notifyExpandingStarted resets the closing state.
+            setIsClosing(true);
+            if (delayed) {
+                mNextCollapseSpeedUpFactor = speedUpFactor;
+                mView.postDelayed(mFlingCollapseRunnable, 120);
+            } else {
+                fling(0, false /* expand */, speedUpFactor, false /* expandBecauseOfFalsing */);
+            }
+        }
+    }
+
+    public boolean canPanelBeCollapsed() {
+        return !isFullyCollapsed() && !mTracking && !mClosing;
+    }
+
+    private final Runnable mFlingCollapseRunnable = () -> fling(0, false /* expand */,
+            mNextCollapseSpeedUpFactor, false /* expandBecauseOfFalsing */);
+
+    public void expand(final boolean animate) {
+        if (!isFullyCollapsed() && !isCollapsing()) {
+            return;
+        }
+
+        mInstantExpanding = true;
+        mAnimateAfterExpanding = animate;
+        mUpdateFlingOnLayout = false;
+        abortAnimations();
+        if (mTracking) {
+            onTrackingStopped(true /* expands */); // The panel is expanded after this call.
+        }
+        if (mExpanding) {
+            notifyExpandingFinished();
+        }
+        updatePanelExpansionAndVisibility();
+
+        // Wait for window manager to pickup the change, so we know the maximum height of the panel
+        // then.
+        mView.getViewTreeObserver().addOnGlobalLayoutListener(
+                new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        if (!mInstantExpanding) {
+                            mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                            return;
+                        }
+                        if (mCentralSurfaces.getNotificationShadeWindowView().isVisibleToUser()) {
+                            mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                            if (mAnimateAfterExpanding) {
+                                notifyExpandingStarted();
+                                beginJankMonitoring();
+                                fling(0, true /* expand */);
+                            } else {
+                                setExpandedFraction(1f);
+                            }
+                            mInstantExpanding = false;
+                        }
+                    }
+                });
+
+        // Make sure a layout really happens.
+        mView.requestLayout();
+    }
+
+    public void instantCollapse() {
+        abortAnimations();
+        setExpandedFraction(0f);
+        if (mExpanding) {
+            notifyExpandingFinished();
+        }
+        if (mInstantExpanding) {
+            mInstantExpanding = false;
+            updatePanelExpansionAndVisibility();
+        }
+    }
+
+    private void abortAnimations() {
+        cancelHeightAnimator();
+        mView.removeCallbacks(mFlingCollapseRunnable);
+    }
+
+    protected abstract void onClosingFinished();
+
+    protected void startUnlockHintAnimation() {
+
+        // We don't need to hint the user if an animation is already running or the user is changing
+        // the expansion.
+        if (mHeightAnimator != null || mTracking) {
+            return;
+        }
+        notifyExpandingStarted();
+        startUnlockHintAnimationPhase1(() -> {
+            notifyExpandingFinished();
+            onUnlockHintFinished();
+            mHintAnimationRunning = false;
+        });
+        onUnlockHintStarted();
+        mHintAnimationRunning = true;
+    }
+
+    protected void onUnlockHintFinished() {
+        mCentralSurfaces.onHintFinished();
+    }
+
+    protected void onUnlockHintStarted() {
+        mCentralSurfaces.onUnlockHintStarted();
+    }
+
+    public boolean isUnlockHintRunning() {
+        return mHintAnimationRunning;
+    }
+
+    /**
+     * Phase 1: Move everything upwards.
+     */
+    private void startUnlockHintAnimationPhase1(final Runnable onAnimationFinished) {
+        float target = Math.max(0, getMaxPanelHeight() - mHintDistance);
+        ValueAnimator animator = createHeightAnimator(target);
+        animator.setDuration(250);
+        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        animator.addListener(new AnimatorListenerAdapter() {
+            private boolean mCancelled;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mCancelled) {
+                    setAnimator(null);
+                    onAnimationFinished.run();
+                } else {
+                    startUnlockHintAnimationPhase2(onAnimationFinished);
+                }
+            }
+        });
+        animator.start();
+        setAnimator(animator);
+
+        final List<ViewPropertyAnimator> indicationAnimators =
+                mKeyguardBottomArea.getIndicationAreaAnimators();
+        for (final ViewPropertyAnimator indicationAreaAnimator : indicationAnimators) {
+            indicationAreaAnimator
+                    .translationY(-mHintDistance)
+                    .setDuration(250)
+                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                    .withEndAction(() -> indicationAreaAnimator
+                            .translationY(0)
+                            .setDuration(450)
+                            .setInterpolator(mBounceInterpolator)
+                            .start())
+                    .start();
+        }
+    }
+
+    private void setAnimator(ValueAnimator animator) {
+        mHeightAnimator = animator;
+        if (animator == null && mPanelUpdateWhenAnimatorEnds) {
+            mPanelUpdateWhenAnimatorEnds = false;
+            requestPanelHeightUpdate();
+        }
+    }
+
+    /**
+     * Phase 2: Bounce down.
+     */
+    private void startUnlockHintAnimationPhase2(final Runnable onAnimationFinished) {
+        ValueAnimator animator = createHeightAnimator(getMaxPanelHeight());
+        animator.setDuration(450);
+        animator.setInterpolator(mBounceInterpolator);
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                setAnimator(null);
+                onAnimationFinished.run();
+                updatePanelExpansionAndVisibility();
+            }
+        });
+        animator.start();
+        setAnimator(animator);
+    }
+
+    private ValueAnimator createHeightAnimator(float targetHeight) {
+        return createHeightAnimator(targetHeight, 0.0f /* performOvershoot */);
+    }
+
+    /**
+     * Create an animator that can also overshoot
+     *
+     * @param targetHeight the target height
+     * @param overshootAmount the amount of overshoot desired
+     */
+    private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) {
+        float startExpansion = mOverExpansion;
+        ValueAnimator animator = ValueAnimator.ofFloat(mExpandedHeight, targetHeight);
+        animator.addUpdateListener(
+                animation -> {
+                    if (overshootAmount > 0.0f
+                            // Also remove the overExpansion when collapsing
+                            || (targetHeight == 0.0f && startExpansion != 0)) {
+                        final float expansion = MathUtils.lerp(
+                                startExpansion,
+                                mPanelFlingOvershootAmount * overshootAmount,
+                                Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+                                        animator.getAnimatedFraction()));
+                        setOverExpansionInternal(expansion, false /* isFromGesture */);
+                    }
+                    setExpandedHeightInternal((float) animation.getAnimatedValue());
+                });
+        return animator;
+    }
+
+    /** Update the visibility of {@link NotificationPanelView} if necessary. */
+    public void updateVisibility() {
+        mView.setVisibility(shouldPanelBeVisible() ? VISIBLE : INVISIBLE);
+    }
+
+    /** Returns true if {@link NotificationPanelView} should be visible. */
+    abstract protected boolean shouldPanelBeVisible();
+
+    /**
+     * Updates the panel expansion and {@link NotificationPanelView} visibility if necessary.
+     *
+     * TODO(b/200063118): Could public calls to this method be replaced with calls to
+     *   {@link #updateVisibility()}? That would allow us to make this method private.
+     */
+    public void updatePanelExpansionAndVisibility() {
+        mPanelExpansionStateManager.onPanelExpansionChanged(
+                mExpandedFraction, isExpanded(), mTracking, mExpansionDragDownAmountPx);
+        updateVisibility();
+    }
+
+    public boolean isExpanded() {
+        return mExpandedFraction > 0f
+                || mInstantExpanding
+                || isPanelVisibleBecauseOfHeadsUp()
+                || mTracking
+                || mHeightAnimator != null
+                && !mIsSpringBackAnimation;
+    }
+
+    protected abstract boolean isPanelVisibleBecauseOfHeadsUp();
+
+    /**
+     * Gets called when the user performs a click anywhere in the empty area of the panel.
+     *
+     * @return whether the panel will be expanded after the action performed by this method
+     */
+    protected boolean onEmptySpaceClick() {
+        if (mHintAnimationRunning) {
+            return true;
+        }
+        return onMiddleClicked();
+    }
+
+    protected abstract boolean onMiddleClicked();
+
+    protected abstract boolean isDozing();
+
+    public void dump(PrintWriter pw, String[] args) {
+        pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%d closing=%s"
+                        + " tracking=%s timeAnim=%s%s "
+                        + "touchDisabled=%s" + "]",
+                this.getClass().getSimpleName(), getExpandedHeight(), getMaxPanelHeight(),
+                mClosing ? "T" : "f", mTracking ? "T" : "f", mHeightAnimator,
+                ((mHeightAnimator != null && mHeightAnimator.isStarted()) ? " (started)" : ""),
+                mTouchDisabled ? "T" : "f"));
+    }
+
+    public void setHeadsUpManager(HeadsUpManagerPhone headsUpManager) {
+        mHeadsUpManager = headsUpManager;
+    }
+
+    public void setIsLaunchAnimationRunning(boolean running) {
+        mIsLaunchAnimationRunning = running;
+    }
+
+    protected void setIsClosing(boolean isClosing) {
+        mClosing = isClosing;
+    }
+
+    protected boolean isClosing() {
+        return mClosing;
+    }
+
+    public void collapseWithDuration(int animationDuration) {
+        mFixedDuration = animationDuration;
+        collapse(false /* delayed */, 1.0f /* speedUpFactor */);
+        mFixedDuration = NO_FIXED_DURATION;
+    }
+
+    public ViewGroup getView() {
+        // TODO: remove this method, or at least reduce references to it.
+        return mView;
+    }
+
+    protected abstract OnLayoutChangeListener createLayoutChangeListener();
+
+    protected abstract TouchHandler createTouchHandler();
+
+    protected OnConfigurationChangedListener createOnConfigurationChangedListener() {
+        return new OnConfigurationChangedListener();
+    }
+
+    public class TouchHandler implements View.OnTouchListener {
+
+        public boolean onInterceptTouchEvent(MotionEvent event) {
+            if (mInstantExpanding || !mNotificationsDragEnabled || mTouchDisabled || (mMotionAborted
+                    && event.getActionMasked() != MotionEvent.ACTION_DOWN)) {
+                return false;
+            }
+
+            /*
+             * If the user drags anywhere inside the panel we intercept it if the movement is
+             * upwards. This allows closing the shade from anywhere inside the panel.
+             *
+             * We only do this if the current content is scrolled to the bottom,
+             * i.e canCollapsePanelOnTouch() is true and therefore there is no conflicting scrolling
+             * gesture
+             * possible.
+             */
+            int pointerIndex = event.findPointerIndex(mTrackingPointer);
+            if (pointerIndex < 0) {
+                pointerIndex = 0;
+                mTrackingPointer = event.getPointerId(pointerIndex);
+            }
+            final float x = event.getX(pointerIndex);
+            final float y = event.getY(pointerIndex);
+            boolean canCollapsePanel = canCollapsePanelOnTouch();
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mCentralSurfaces.userActivity();
+                    mAnimatingOnDown = mHeightAnimator != null && !mIsSpringBackAnimation;
+                    mMinExpandHeight = 0.0f;
+                    mDownTime = mSystemClock.uptimeMillis();
+                    if (mAnimatingOnDown && mClosing && !mHintAnimationRunning) {
+                        cancelHeightAnimator();
+                        mTouchSlopExceeded = true;
+                        return true;
+                    }
+                    mInitialExpandY = y;
+                    mInitialExpandX = x;
+                    mTouchStartedInEmptyArea = !isInContentBounds(x, y);
+                    mTouchSlopExceeded = mTouchSlopExceededBeforeDown;
+                    mMotionAborted = false;
+                    mPanelClosedOnDown = isFullyCollapsed();
+                    mCollapsedAndHeadsUpOnDown = false;
+                    mHasLayoutedSinceDown = false;
+                    mUpdateFlingOnLayout = false;
+                    mTouchAboveFalsingThreshold = false;
+                    addMovement(event);
+                    break;
+                case MotionEvent.ACTION_POINTER_UP:
+                    final int upPointer = event.getPointerId(event.getActionIndex());
+                    if (mTrackingPointer == upPointer) {
+                        // gesture is ongoing, find a new pointer to track
+                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                        mTrackingPointer = event.getPointerId(newIndex);
+                        mInitialExpandX = event.getX(newIndex);
+                        mInitialExpandY = event.getY(newIndex);
+                    }
+                    break;
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                        mMotionAborted = true;
+                        mVelocityTracker.clear();
+                    }
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    final float h = y - mInitialExpandY;
+                    addMovement(event);
+                    final boolean openShadeWithoutHun =
+                            mPanelClosedOnDown && !mCollapsedAndHeadsUpOnDown;
+                    if (canCollapsePanel || mTouchStartedInEmptyArea || mAnimatingOnDown
+                            || openShadeWithoutHun) {
+                        float hAbs = Math.abs(h);
+                        float touchSlop = getTouchSlop(event);
+                        if ((h < -touchSlop
+                                || ((openShadeWithoutHun || mAnimatingOnDown) && hAbs > touchSlop))
+                                && hAbs > Math.abs(x - mInitialExpandX)) {
+                            cancelHeightAnimator();
+                            startExpandMotion(x, y, true /* startTracking */, mExpandedHeight);
+                            return true;
+                        }
+                    }
+                    break;
+                case MotionEvent.ACTION_CANCEL:
+                case MotionEvent.ACTION_UP:
+                    mVelocityTracker.clear();
+                    break;
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            if (mInstantExpanding) {
+                mShadeLog.logMotionEvent(event, "onTouch: touch ignored due to instant expanding");
+                return false;
+            }
+            if (mTouchDisabled  && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
+                mShadeLog.logMotionEvent(event, "onTouch: non-cancel action, touch disabled");
+                return false;
+            }
+            if (mMotionAborted && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+                mShadeLog.logMotionEvent(event, "onTouch: non-down action, motion was aborted");
+                return false;
+            }
+
+            // If dragging should not expand the notifications shade, then return false.
+            if (!mNotificationsDragEnabled) {
+                if (mTracking) {
+                    // Turn off tracking if it's on or the shade can get stuck in the down position.
+                    onTrackingStopped(true /* expand */);
+                }
+                mShadeLog.logMotionEvent(event, "onTouch: drag not enabled");
+                return false;
+            }
+
+            // On expanding, single mouse click expands the panel instead of dragging.
+            if (isFullyCollapsed() && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
+                if (event.getAction() == MotionEvent.ACTION_UP) {
+                    expand(true);
+                }
+                return true;
+            }
+
+            /*
+             * We capture touch events here and update the expand height here in case according to
+             * the users fingers. This also handles multi-touch.
+             *
+             * Flinging is also enabled in order to open or close the shade.
+             */
+
+            int pointerIndex = event.findPointerIndex(mTrackingPointer);
+            if (pointerIndex < 0) {
+                pointerIndex = 0;
+                mTrackingPointer = event.getPointerId(pointerIndex);
+            }
+            final float x = event.getX(pointerIndex);
+            final float y = event.getY(pointerIndex);
+
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                mGestureWaitForTouchSlop = shouldGestureWaitForTouchSlop();
+                mIgnoreXTouchSlop = true;
+            }
+
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
+                    mMinExpandHeight = 0.0f;
+                    mPanelClosedOnDown = isFullyCollapsed();
+                    mHasLayoutedSinceDown = false;
+                    mUpdateFlingOnLayout = false;
+                    mMotionAborted = false;
+                    mDownTime = mSystemClock.uptimeMillis();
+                    mTouchAboveFalsingThreshold = false;
+                    mCollapsedAndHeadsUpOnDown =
+                            isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp();
+                    addMovement(event);
+                    boolean regularHeightAnimationRunning = mHeightAnimator != null
+                            && !mHintAnimationRunning && !mIsSpringBackAnimation;
+                    if (!mGestureWaitForTouchSlop || regularHeightAnimationRunning) {
+                        mTouchSlopExceeded = regularHeightAnimationRunning
+                                        || mTouchSlopExceededBeforeDown;
+                        cancelHeightAnimator();
+                        onTrackingStarted();
+                    }
+                    if (isFullyCollapsed() && !mHeadsUpManager.hasPinnedHeadsUp()
+                            && !mCentralSurfaces.isBouncerShowing()) {
+                        startOpening(event);
+                    }
+                    break;
+
+                case MotionEvent.ACTION_POINTER_UP:
+                    final int upPointer = event.getPointerId(event.getActionIndex());
+                    if (mTrackingPointer == upPointer) {
+                        // gesture is ongoing, find a new pointer to track
+                        final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+                        final float newY = event.getY(newIndex);
+                        final float newX = event.getX(newIndex);
+                        mTrackingPointer = event.getPointerId(newIndex);
+                        mHandlingPointerUp = true;
+                        startExpandMotion(newX, newY, true /* startTracking */, mExpandedHeight);
+                        mHandlingPointerUp = false;
+                    }
+                    break;
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+                        mMotionAborted = true;
+                        endMotionEvent(event, x, y, true /* forceCancel */);
+                        return false;
+                    }
+                    break;
+                case MotionEvent.ACTION_MOVE:
+                    addMovement(event);
+                    float h = y - mInitialExpandY;
+
+                    // If the panel was collapsed when touching, we only need to check for the
+                    // y-component of the gesture, as we have no conflicting horizontal gesture.
+                    if (Math.abs(h) > getTouchSlop(event)
+                            && (Math.abs(h) > Math.abs(x - mInitialExpandX)
+                            || mIgnoreXTouchSlop)) {
+                        mTouchSlopExceeded = true;
+                        if (mGestureWaitForTouchSlop && !mTracking && !mCollapsedAndHeadsUpOnDown) {
+                            if (mInitialOffsetOnTouch != 0f) {
+                                startExpandMotion(x, y, false /* startTracking */, mExpandedHeight);
+                                h = 0;
+                            }
+                            cancelHeightAnimator();
+                            onTrackingStarted();
+                        }
+                    }
+                    float newHeight = Math.max(0, h + mInitialOffsetOnTouch);
+                    newHeight = Math.max(newHeight, mMinExpandHeight);
+                    if (-h >= getFalsingThreshold()) {
+                        mTouchAboveFalsingThreshold = true;
+                        mUpwardsWhenThresholdReached = isDirectionUpwards(x, y);
+                    }
+                    if ((!mGestureWaitForTouchSlop || mTracking) && !isTrackingBlocked()) {
+                        // Count h==0 as part of swipe-up,
+                        // otherwise {@link NotificationStackScrollLayout}
+                        // wrongly enables stack height updates at the start of lockscreen swipe-up
+                        mAmbientState.setSwipingUp(h <= 0);
+                        setExpandedHeightInternal(newHeight);
+                    }
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    addMovement(event);
+                    endMotionEvent(event, x, y, false /* forceCancel */);
+                    // mHeightAnimator is null, there is no remaining frame, ends instrumenting.
+                    if (mHeightAnimator == null) {
+                        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
+                            endJankMonitoring();
+                        } else {
+                            cancelJankMonitoring();
+                        }
+                    }
+                    break;
+            }
+            return !mGestureWaitForTouchSlop || mTracking;
+        }
+    }
+
+    protected abstract class OnLayoutChangeListener implements View.OnLayoutChangeListener {
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+                int oldTop, int oldRight, int oldBottom) {
+            requestPanelHeightUpdate();
+            mHasLayoutedSinceDown = true;
+            if (mUpdateFlingOnLayout) {
+                abortAnimations();
+                fling(mUpdateFlingVelocity, true /* expands */);
+                mUpdateFlingOnLayout = false;
+            }
+        }
+    }
+
+    public class OnConfigurationChangedListener implements
+            NotificationPanelView.OnConfigurationChangedListener {
+        @Override
+        public void onConfigurationChanged(Configuration newConfig) {
+            loadDimens();
+        }
+    }
+
+    private void beginJankMonitoring() {
+        if (mInteractionJankMonitor == null) {
+            return;
+        }
+        InteractionJankMonitor.Configuration.Builder builder =
+                InteractionJankMonitor.Configuration.Builder.withView(
+                                InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
+                                mView)
+                        .setTag(isFullyCollapsed() ? "Expand" : "Collapse");
+        mInteractionJankMonitor.begin(builder);
+    }
+
+    private void endJankMonitoring() {
+        if (mInteractionJankMonitor == null) {
+            return;
+        }
+        InteractionJankMonitor.getInstance().end(
+                InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+    }
+
+    private void cancelJankMonitoring() {
+        if (mInteractionJankMonitor == null) {
+            return;
+        }
+        InteractionJankMonitor.getInstance().cancel(
+                InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE);
+    }
+
+    protected float getExpansionFraction() {
+        return mExpandedFraction;
+    }
+
+    protected PanelExpansionStateManager getPanelExpansionStateManager() {
+        return mPanelExpansionStateManager;
+    }
+}
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/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index ee79a4d..9d4a27c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -50,7 +50,6 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
 import android.view.InsetsState.InternalInsetsType;
@@ -74,7 +73,6 @@
 import com.android.systemui.tracing.ProtoTracer;
 
 import java.io.FileOutputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -150,7 +148,6 @@
     private static final int MSG_TRACING_STATE_CHANGED             = 54 << MSG_SHIFT;
     private static final int MSG_SUPPRESS_AMBIENT_DISPLAY          = 55 << MSG_SHIFT;
     private static final int MSG_REQUEST_WINDOW_MAGNIFICATION_CONNECTION = 56 << MSG_SHIFT;
-    private static final int MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND = 57 << MSG_SHIFT;
     //TODO(b/169175022) Update name and when feature name is locked.
     private static final int MSG_EMERGENCY_ACTION_LAUNCH_GESTURE      = 58 << MSG_SHIFT;
     private static final int MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED = 59 << MSG_SHIFT;
@@ -423,11 +420,6 @@
         default void requestWindowMagnificationConnection(boolean connect) { }
 
         /**
-         * Handles a window manager shell logging command.
-         */
-        default void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {}
-
-        /**
          * @see IStatusBar#setNavigationBarLumaSamplingEnabled(int, boolean)
          */
         default void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {}
@@ -1140,17 +1132,6 @@
     }
 
     @Override
-    public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
-        synchronized (mLock) {
-            SomeArgs internalArgs = SomeArgs.obtain();
-            internalArgs.arg1 = args;
-            internalArgs.arg2 = outFd;
-            mHandler.obtainMessage(MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND, internalArgs)
-                    .sendToTarget();
-        }
-    }
-
-    @Override
     public void suppressAmbientDisplay(boolean suppress) {
         synchronized (mLock) {
             mHandler.obtainMessage(MSG_SUPPRESS_AMBIENT_DISPLAY, suppress).sendToTarget();
@@ -1634,18 +1615,6 @@
                         mCallbacks.get(i).requestWindowMagnificationConnection((Boolean) msg.obj);
                     }
                     break;
-                case MSG_HANDLE_WINDOW_MANAGER_LOGGING_COMMAND:
-                    args = (SomeArgs) msg.obj;
-                    try (ParcelFileDescriptor pfd = (ParcelFileDescriptor) args.arg2) {
-                        for (int i = 0; i < mCallbacks.size(); i++) {
-                            mCallbacks.get(i).handleWindowManagerLoggingCommand(
-                                    (String[]) args.arg1, pfd);
-                        }
-                    } catch (IOException e) {
-                        Log.e(TAG, "Failed to handle logging command", e);
-                    }
-                    args.recycle();
-                    break;
                 case MSG_SET_NAVIGATION_BAR_LUMA_SAMPLING_ENABLED:
                     for (int i = 0; i < mCallbacks.size(); i++) {
                         mCallbacks.get(i).setNavigationBarLumaSamplingEnabled(msg.arg1,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index b9684fc..3d161d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -24,6 +24,8 @@
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -73,6 +75,7 @@
     }
 
     @Override
+    @NonNull
     public ExpandableViewState createExpandableViewState() {
         return new EmptyShadeViewState();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 87f8a03..408c61f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,9 +19,16 @@
 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_FIRST_FRAME_RECEIVED;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START;
+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;
 
+import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
+import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -75,6 +82,7 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.R;
+import com.android.systemui.biometrics.BiometricMessageDeferral;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -175,7 +183,7 @@
     private boolean mBatteryPresent = true;
     private long mChargingTimeRemaining;
     private String mBiometricErrorMessageToShowOnScreenOn;
-    private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
+    private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
     private boolean mInited;
 
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -246,11 +254,11 @@
         mScreenLifecycle = screenLifecycle;
         mScreenLifecycle.addObserver(mScreenObserver);
 
-        mCoExFaceHelpMsgIdsToShow = new HashSet<>();
+        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) {
@@ -428,9 +436,9 @@
             if (info == null) {
                 // Use the current user owner information if enabled.
                 final boolean ownerInfoEnabled = mLockPatternUtils.isOwnerInfoEnabled(
-                        KeyguardUpdateMonitor.getCurrentUser());
+                        getCurrentUser());
                 if (ownerInfoEnabled) {
-                    info = mLockPatternUtils.getOwnerInfo(KeyguardUpdateMonitor.getCurrentUser());
+                    info = mLockPatternUtils.getOwnerInfo(getCurrentUser());
                 }
             }
 
@@ -595,7 +603,7 @@
 
     private void updateLockScreenLogoutView() {
         final boolean shouldShowLogout = mKeyguardUpdateMonitor.isLogoutEnabled()
-                && KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM;
+                && getCurrentUser() != UserHandle.USER_SYSTEM;
         if (shouldShowLogout) {
             mRotateTextViewController.updateIndication(
                     INDICATION_TYPE_LOGOUT,
@@ -610,7 +618,7 @@
                                 if (mFalsingManager.isFalseTap(LOW_PENALTY)) {
                                     return;
                                 }
-                                int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+                                int currentUserId = getCurrentUser();
                                 mDevicePolicyManager.logoutUser();
                             })
                             .build(),
@@ -684,11 +692,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();
     }
@@ -767,7 +775,7 @@
         mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
         hideBiometricMessageDelayed(
                 mBiometricMessageFollowUp != null
-                        ? DEFAULT_HIDE_DELAY_MS * 2
+                        ? IMPORTANT_MSG_MIN_DURATION * 2
                         : DEFAULT_HIDE_DELAY_MS
         );
 
@@ -847,7 +855,7 @@
         mTopIndicationView.setVisibility(GONE);
         mTopIndicationView.setText(null);
         mLockScreenIndicationView.setVisibility(View.VISIBLE);
-        updateLockScreenIndications(animate, KeyguardUpdateMonitor.getCurrentUser());
+        updateLockScreenIndications(animate, getCurrentUser());
     }
 
     protected String computePowerIndication() {
@@ -915,7 +923,7 @@
     public void showActionToUnlock() {
         if (mDozing
                 && !mKeyguardUpdateMonitor.getUserCanSkipBouncer(
-                        KeyguardUpdateMonitor.getCurrentUser())) {
+                        getCurrentUser())) {
             return;
         }
 
@@ -924,11 +932,11 @@
                 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(
-                    KeyguardUpdateMonitor.getCurrentUser());
+                    getCurrentUser());
             if (canSkipBouncer) {
                 final boolean faceAuthenticated = mKeyguardUpdateMonitor.getIsFaceAuthenticated();
                 final boolean udfpsSupported = mKeyguardUpdateMonitor.isUdfpsSupported();
@@ -987,7 +995,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);
     }
 
@@ -1045,24 +1053,51 @@
                 return;
             }
 
-            boolean showActionToUnlock =
-                    msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
-            if (biometricSourceType == BiometricSourceType.FACE
-                    && !showActionToUnlock
-                    && mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                            KeyguardUpdateMonitor.getCurrentUser())
-                    && !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
+            if (biometricSourceType == FACE) {
+                if (msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED) {
+                    mFaceAcquiredMessageDeferral.reset();
+                } else {
+                    mFaceAcquiredMessageDeferral.processMessage(msgId, helpString);
+                    if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) {
+                        return;
+                    }
+                }
+            }
+
+            final boolean faceAuthSoftError = biometricSourceType == FACE
+                    && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
+            final boolean faceAuthFailed = biometricSourceType == FACE
+                    && msgId == BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; // ran through matcher & failed
+            final boolean isUnlockWithFingerprintPossible =
+                    mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+                            getCurrentUser());
+            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) {
-                showBiometricMessage(helpString);
-            } else if (showActionToUnlock) {
+                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)
+                    );
+                } else {
+                    showBiometricMessage(helpString);
+                }
+            } else if (faceAuthFailed) {
+                // show action to unlock
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
                         TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
             } else {
@@ -1076,41 +1111,51 @@
         @Override
         public void onBiometricError(int msgId, String errString,
                 BiometricSourceType biometricSourceType) {
-            if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
-                return;
+            CharSequence deferredFaceMessage = null;
+            if (biometricSourceType == FACE) {
+                deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
+                mFaceAcquiredMessageDeferral.reset();
             }
 
-            if (biometricSourceType == 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 == 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(
                         KeyguardUpdateMonitor.getCurrentUser())) {
-                    // no message if fingerprint is also enrolled
+                    // 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 {
@@ -1120,10 +1165,12 @@
 
         private boolean shouldSuppressBiometricError(int msgId,
                 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
-            if (biometricSourceType == BiometricSourceType.FINGERPRINT)
+            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                 return shouldSuppressFingerprintError(msgId, updateMonitor);
-            if (biometricSourceType == BiometricSourceType.FACE)
+            }
+            if (biometricSourceType == FACE) {
                 return shouldSuppressFaceError(msgId, updateMonitor);
+            }
             return false;
         }
 
@@ -1146,13 +1193,14 @@
             // 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);
         }
 
 
         @Override
         public void onTrustChanged(int userId) {
-            if (KeyguardUpdateMonitor.getCurrentUser() != userId) {
+            if (getCurrentUser() != userId) {
                 return;
             }
             updateDeviceEntryIndication(false);
@@ -1172,7 +1220,7 @@
         @Override
         public void onBiometricRunningStateChanged(boolean running,
                 BiometricSourceType biometricSourceType) {
-            if (running && biometricSourceType == BiometricSourceType.FACE) {
+            if (running && biometricSourceType == FACE) {
                 // Let's hide any previous messages when authentication starts, otherwise
                 // multiple auth attempts would overlap.
                 hideBiometricMessage();
@@ -1185,10 +1233,11 @@
                 boolean isStrongBiometric) {
             super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
             hideBiometricMessage();
-
-            if (biometricSourceType == BiometricSourceType.FACE
-                    && !mKeyguardBypassController.canBypass()) {
-                showActionToUnlock();
+            if (biometricSourceType == FACE) {
+                mFaceAcquiredMessageDeferral.reset();
+                if (!mKeyguardBypassController.canBypass()) {
+                    showActionToUnlock();
+                }
             }
         }
 
@@ -1259,4 +1308,14 @@
             }
         }
     };
+
+    private final BiometricMessageDeferral mFaceAcquiredMessageDeferral =
+            new BiometricMessageDeferral(
+                    Set.of(
+                            FACE_ACQUIRED_GOOD,
+                            FACE_ACQUIRED_START,
+                            FACE_ACQUIRED_FIRST_FRAME_RECEIVED
+                    ),
+                    Set.of(FACE_ACQUIRED_TOO_DARK)
+            );
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 0a616c0..9d2750f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -143,13 +143,13 @@
 
 class CircleReveal(
     /** X-value of the circle center of the reveal. */
-    val centerX: Float,
+    val centerX: Int,
     /** Y-value of the circle center of the reveal. */
-    val centerY: Float,
+    val centerY: Int,
     /** Radius of initial state of circle reveal */
-    val startRadius: Float,
+    val startRadius: Int,
     /** Radius of end state of circle reveal */
-    val endRadius: Float
+    val endRadius: Int
 ) : LightRevealEffect {
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
         // reveal amount updates already have an interpolator, so we intentionally use the
@@ -350,7 +350,7 @@
      * This method does not call [invalidate] - you should do so once you're done changing
      * properties.
      */
-    public fun setRevealGradientBounds(left: Float, top: Float, right: Float, bottom: Float) {
+    fun setRevealGradientBounds(left: Float, top: Float, right: Float, bottom: Float) {
         revealGradientWidth = right - left
         revealGradientHeight = bottom - top
 
@@ -387,4 +387,4 @@
             getColorWithAlpha(revealGradientEndColor, revealGradientEndColorAlpha),
             PorterDuff.Mode.MULTIPLY)
     }
-}
\ No newline at end of file
+}
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/NotificationInteractionTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt
index 2ca1beb..7b49ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt
@@ -1,7 +1,6 @@
 package com.android.systemui.statusbar
 
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import javax.inject.Inject
@@ -12,14 +11,12 @@
  */
 @SysUISingleton
 class NotificationInteractionTracker @Inject constructor(
-    private val clicker: NotificationClickNotifier,
-    private val entryManager: NotificationEntryManager
+    clicker: NotificationClickNotifier,
 ) : NotifCollectionListener, NotificationInteractionListener {
     private val interactions = mutableMapOf<String, Boolean>()
 
     init {
         clicker.addNotificationInteractionListener(this)
-        entryManager.addCollectionListener(this)
     }
 
     fun hasUserInteractedWith(key: String): Boolean {
@@ -38,5 +35,3 @@
         interactions[key] = true
     }
 }
-
-private const val TAG = "NotificationInteractionTracker"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
index d1bc14f..d908243 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManager.java
@@ -50,12 +50,6 @@
     void addUserChangedListener(UserChangedListener listener);
 
     /**
-     * Registers a [KeyguardNotificationSuppressor] that will be consulted during
-     * {@link #shouldShowOnKeyguard(NotificationEntry)}
-     */
-    void addKeyguardNotificationSuppressor(KeyguardNotificationSuppressor suppressor);
-
-    /**
      * Removes a listener previously registered with
      * {@link #addUserChangedListener(UserChangedListener)}
      */
@@ -63,14 +57,8 @@
 
     SparseArray<UserInfo> getCurrentProfiles();
 
-    void setLockscreenPublicMode(boolean isProfilePublic, int userId);
-
     boolean shouldShowLockscreenNotifications();
 
-    boolean shouldHideNotifications(int userId);
-    boolean shouldHideNotifications(String key);
-    boolean shouldShowOnKeyguard(NotificationEntry entry);
-
     boolean isAnyProfilePublicMode();
 
     void updatePublicMode();
@@ -108,11 +96,6 @@
         default void onUserRemoved(int userId) {}
     }
 
-    /** Used to hide notifications on the lockscreen */
-    interface KeyguardNotificationSuppressor {
-        boolean shouldSuppressOnKeyguard(NotificationEntry entry);
-    }
-
     /**
      * Notified when any state pertaining to Notifications has changed; any methods pertaining to
      * notifications should be re-queried.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index f4ca7ed..8699441 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -15,17 +15,13 @@
  */
 package com.android.systemui.statusbar;
 
-import static android.app.Notification.VISIBILITY_SECRET;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
 
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.app.Notification;
-import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -42,9 +38,10 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -54,7 +51,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -88,9 +84,6 @@
     private final SecureSettings mSecureSettings;
     private final Object mLock = new Object();
 
-    // Lazy
-    private NotificationEntryManager mEntryManager;
-
     private final Lazy<NotificationVisibilityProvider> mVisibilityProviderLazy;
     private final Lazy<CommonNotifCollection> mCommonNotifCollectionLazy;
     private final DevicePolicyManager mDevicePolicyManager;
@@ -110,7 +103,6 @@
     private LockPatternUtils mLockPatternUtils;
     protected KeyguardManager mKeyguardManager;
     private int mState = StatusBarState.SHADE;
-    private List<KeyguardNotificationSuppressor> mKeyguardSuppressors = new ArrayList<>();
     private final ListenerSet<NotificationStateChangedListener> mNotifStateChangedListeners =
             new ListenerSet<>();
 
@@ -123,7 +115,6 @@
                     isCurrentProfile(getSendingUserId())) {
                 mUsersAllowingPrivateNotifications.clear();
                 updateLockscreenNotificationSetting();
-                getEntryManager().updateNotifications("ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED");
                 // TODO(b/231976036): Consolidate pipeline invalidations related to this event
                 // notifyNotificationStateChanged();
             }
@@ -144,10 +135,6 @@
 
                     updateLockscreenNotificationSetting();
                     updatePublicMode();
-                    // The filtering needs to happen before the update call below in order to
-                    // make sure
-                    // the presenter has the updated notifications from the new user
-                    getEntryManager().reapplyFilterAndSort("user switched");
                     mPresenter.onUserSwitched(mCurrentUserId);
 
                     for (UserChangedListener listener : mListeners) {
@@ -204,13 +191,6 @@
     protected ContentObserver mSettingsObserver;
     private boolean mHideSilentNotificationsOnLockscreen;
 
-    private NotificationEntryManager getEntryManager() {
-        if (mEntryManager == null) {
-            mEntryManager = Dependency.get(NotificationEntryManager.class);
-        }
-        return mEntryManager;
-    }
-
     @Inject
     public NotificationLockscreenUserManagerImpl(Context context,
             BroadcastDispatcher broadcastDispatcher,
@@ -257,8 +237,6 @@
                 mUsersAllowingNotifications.clear();
                 // ... and refresh all the notifications
                 updateLockscreenNotificationSetting();
-                getEntryManager().updateNotifications("LOCK_SCREEN_SHOW_NOTIFICATIONS,"
-                        + " or LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS change");
                 notifyNotificationStateChanged();
             }
         };
@@ -268,8 +246,6 @@
             public void onChange(boolean selfChange) {
                 updateLockscreenNotificationSetting();
                 if (mDeviceProvisionedController.isDeviceProvisioned()) {
-                    getEntryManager().updateNotifications("LOCK_SCREEN_ALLOW_REMOTE_INPUT"
-                            + " or ZEN_MODE change");
                     // TODO(b/231976036): Consolidate pipeline invalidations related to this event
                     // notifyNotificationStateChanged();
                 }
@@ -344,67 +320,6 @@
         }
     }
 
-    /**
-     * Returns true if notifications are temporarily disabled for this user for security reasons,
-     * regardless of the normal settings for that user.
-     */
-    private boolean shouldTemporarilyHideNotifications(int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            userId = mCurrentUserId;
-        }
-        boolean inLockdown = Dependency.get(KeyguardUpdateMonitor.class).isUserInLockdown(userId);
-        mUsersInLockdownLatestResult.put(userId, inLockdown);
-        return inLockdown;
-    }
-
-    /**
-     * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
-     * If so, notifications should be hidden.
-     */
-    public boolean shouldHideNotifications(int userId) {
-        boolean hide = isLockscreenPublicMode(userId) && !userAllowsNotificationsInPublic(userId)
-                || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId))
-                || shouldTemporarilyHideNotifications(userId);
-        mShouldHideNotifsLatestResult.put(userId, hide);
-        return hide;
-    }
-
-    /**
-     * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
-     * package-specific override.
-     */
-    public boolean shouldHideNotifications(String key) {
-        if (mCommonNotifCollectionLazy.get() == null) {
-            Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable());
-            return true;
-        }
-        NotificationEntry visibleEntry = mCommonNotifCollectionLazy.get().getEntry(key);
-        return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
-                && visibleEntry.getRanking().getLockscreenVisibilityOverride() == VISIBILITY_SECRET;
-    }
-
-    public boolean shouldShowOnKeyguard(NotificationEntry entry) {
-        if (mCommonNotifCollectionLazy.get() == null) {
-            Log.wtf(TAG, "mCommonNotifCollectionLazy was null!", new Throwable());
-            return false;
-        }
-        for (int i = 0; i < mKeyguardSuppressors.size(); i++) {
-            if (mKeyguardSuppressors.get(i).shouldSuppressOnKeyguard(entry)) {
-                return false;
-            }
-        }
-        boolean exceedsPriorityThreshold;
-        if (mHideSilentNotificationsOnLockscreen) {
-            exceedsPriorityThreshold =
-                    entry.getBucket() == BUCKET_MEDIA_CONTROLS
-                            || (entry.getBucket() != BUCKET_SILENT
-                            && entry.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT);
-        } else {
-            exceedsPriorityThreshold = !entry.getRanking().isAmbient();
-        }
-        return mShowLockscreenNotifications && exceedsPriorityThreshold;
-    }
-
     private void setShowLockscreenNotifications(boolean show) {
         mShowLockscreenNotifications = show;
     }
@@ -491,7 +406,8 @@
     /**
      * Save the current "public" (locked and secure) state of the lockscreen.
      */
-    public void setLockscreenPublicMode(boolean publicMode, int userId) {
+    @VisibleForTesting
+    void setLockscreenPublicMode(boolean publicMode, int userId) {
         mLockscreenPublicMode.put(userId, publicMode);
     }
 
@@ -660,7 +576,6 @@
             setLockscreenPublicMode(isProfilePublic, userId);
             mUsersWithSeparateWorkChallenge.put(userId, needsSeparateChallenge);
         }
-        getEntryManager().updateNotifications("NotificationLockscreenUserManager.updatePublicMode");
         // TODO(b/234738798): Migrate KeyguardNotificationVisibilityProvider to use this listener
         if (!mLockscreenPublicMode.equals(oldPublicModes)
                 || !mUsersWithSeparateWorkChallenge.equals(oldWorkChallenges)) {
@@ -674,11 +589,6 @@
     }
 
     @Override
-    public void addKeyguardNotificationSuppressor(KeyguardNotificationSuppressor suppressor) {
-        mKeyguardSuppressors.add(suppressor);
-    }
-
-    @Override
     public void removeUserChangedListener(UserChangedListener listener) {
         mListeners.remove(listener);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index d74d408..f668528 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -53,8 +53,6 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.dagger.CentralSurfacesDependenciesModule;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -256,7 +254,6 @@
             NotificationLockscreenUserManager lockscreenUserManager,
             SmartReplyController smartReplyController,
             NotificationVisibilityProvider visibilityProvider,
-            NotificationEntryManager notificationEntryManager,
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             StatusBarStateController statusBarStateController,
             RemoteInputUriController remoteInputUriController,
@@ -279,25 +276,6 @@
         mClickNotifier = clickNotifier;
 
         dumpManager.registerDumpable(this);
-
-        notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
-            @Override
-            public void onPreEntryUpdated(NotificationEntry entry) {
-                // Mark smart replies as sent whenever a notification is updated - otherwise the
-                // smart replies are never marked as sent.
-                mSmartReplyController.stopSending(entry);
-            }
-
-            @Override
-            public void onEntryRemoved(
-                    @Nullable NotificationEntry entry,
-                    NotificationVisibility visibility,
-                    boolean removedByUser,
-                    int reason) {
-                // We're removing the notification, the smart controller can forget about it.
-                mSmartReplyController.stopSending(entry);
-            }
-        });
     }
 
     /** Add a listener for various remote input events.  Works with NEW pipeline only. */
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 2214287..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;
@@ -29,6 +31,8 @@
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.SystemBarUtils;
 import com.android.systemui.R;
@@ -88,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() {
@@ -153,6 +163,7 @@
     }
 
     @Override
+    @NonNull
     public ExpandableViewState createExpandableViewState() {
         return new ShelfState();
     }
@@ -172,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/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index a57d849b2..25c6dce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -38,6 +38,7 @@
 import com.android.systemui.DualToneHandler;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 
 import java.util.ArrayList;
@@ -64,6 +65,15 @@
 
     /**
      * Designated constructor
+     *
+     * This view is special, in that it is the only view in SystemUI that allows for a configuration
+     * override on a MCC/MNC-basis. This means that for every mobile view inflated, we have to
+     * construct a context with that override, since the resource system doesn't have a way to
+     * handle this for us.
+     *
+     * @param context A context with resources configured by MCC/MNC
+     * @param slot The string key defining which slot this icon refers to. Always "mobile" for the
+     *             mobile icon
      */
     public static StatusBarMobileView fromContext(
             Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
index c74621d..867be1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/VibratorHelper.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.media.AudioAttributes;
+import android.os.Process;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -33,6 +34,7 @@
 import javax.inject.Inject;
 
 /**
+ *
  */
 @SysUISingleton
 public class VibratorHelper {
@@ -40,9 +42,18 @@
     private final Vibrator mVibrator;
     private static final VibrationAttributes TOUCH_VIBRATION_ATTRIBUTES =
             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_TOUCH);
+
+    private static final VibrationEffect BIOMETRIC_SUCCESS_VIBRATION_EFFECT =
+            VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+    private static final VibrationEffect BIOMETRIC_ERROR_VIBRATION_EFFECT =
+            VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
+    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
+
     private final Executor mExecutor;
 
     /**
+     *
      */
     @Inject
     public VibratorHelper(@Nullable Vibrator vibrator, @Background Executor executor) {
@@ -109,4 +120,23 @@
         }
         mExecutor.execute(mVibrator::cancel);
     }
+
+    /**
+     * Perform vibration when biometric authentication success
+     */
+    public void vibrateAuthSuccess(String reason) {
+        vibrate(Process.myUid(),
+                "com.android.systemui",
+                BIOMETRIC_SUCCESS_VIBRATION_EFFECT, reason,
+                HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
+    }
+
+    /**
+     * Perform vibration when biometric authentication error
+     */
+    public void vibrateAuthError(String reason) {
+        vibrate(Process.myUid(), "com.android.systemui",
+                BIOMETRIC_ERROR_VIBRATION_EFFECT, reason,
+                HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
new file mode 100644
index 0000000..a02dd34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProvider.kt
@@ -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.systemui.statusbar.connectivity.ui
+
+import android.content.Context
+import android.content.res.Configuration
+import android.os.Bundle
+import android.telephony.SubscriptionInfo
+import android.view.ContextThemeWrapper
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.connectivity.NetworkController
+import com.android.systemui.statusbar.connectivity.SignalCallback
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Every subscriptionId can have its own CarrierConfig associated with it, so we have to create our
+ * own [Configuration] and track resources based on the full set of available mcc-mnc combinations.
+ *
+ * (for future reference: b/240555502 is the initiating bug for this)
+ */
+@SysUISingleton
+class MobileContextProvider
+@Inject
+constructor(
+    networkController: NetworkController,
+    dumpManager: DumpManager,
+    private val demoModeController: DemoModeController,
+) : Dumpable, DemoMode {
+    private val subscriptions = mutableMapOf<Int, SubscriptionInfo>()
+    private val signalCallback =
+        object : SignalCallback {
+            override fun setSubs(subs: List<SubscriptionInfo>) {
+                subscriptions.clear()
+                subs.forEach { info -> subscriptions[info.subscriptionId] = info }
+            }
+        }
+
+    // These should always be null when not in demo mode
+    private var demoMcc: Int? = null
+    private var demoMnc: Int? = null
+
+    init {
+        networkController.addCallback(signalCallback)
+        dumpManager.registerDumpable(this)
+        demoModeController.addCallback(this)
+    }
+
+    /**
+     * @return a context with the MCC/MNC [Configuration] values corresponding to this
+     * subscriptionId
+     */
+    fun getMobileContextForSub(subId: Int, context: Context): Context {
+        if (demoModeController.isInDemoMode) {
+            return createMobileContextForDemoMode(context)
+        }
+
+        // Fail back to the given context if no sub exists
+        val info = subscriptions[subId] ?: return context
+
+        return createCarrierConfigContext(context, info.mcc, info.mnc)
+    }
+
+    /** For Demo mode (for now), just apply the same MCC/MNC override for all subIds */
+    private fun createMobileContextForDemoMode(context: Context): Context {
+        return createCarrierConfigContext(context, demoMcc ?: 0, demoMnc ?: 0)
+    }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println(
+            "Subscriptions below will be inflated with a configuration context with " +
+                "MCC/MNC overrides"
+        )
+        subscriptions.forEach { (subId, info) ->
+            pw.println("  Subscription with subId($subId) with MCC/MNC(${info.mcc}/${info.mnc})")
+        }
+        pw.println("  MCC override: ${demoMcc ?: "(none)"}")
+        pw.println("  MNC override: ${demoMnc ?: "(none)"}")
+    }
+
+    override fun demoCommands(): List<String> {
+        return listOf(COMMAND_NETWORK)
+    }
+
+    override fun onDemoModeFinished() {
+        demoMcc = null
+        demoMnc = null
+    }
+
+    override fun dispatchDemoCommand(command: String, args: Bundle) {
+        val mccmnc = args.getString("mccmnc") ?: return
+        // Only length 5/6 strings are valid
+        if (!(mccmnc.length == 5 || mccmnc.length == 6)) {
+            return
+        }
+
+        // MCC is always the first 3 digits, and mnc is the last 2 or 3
+        demoMcc = mccmnc.subSequence(0, 3).toString().toInt()
+        demoMnc = mccmnc.subSequence(3, mccmnc.length).toString().toInt()
+    }
+
+    companion object {
+        /**
+         * Creates a context based on this [SubscriptionInfo]'s MCC/MNC values, allowing the overlay
+         * system to properly load different carrier's iconography
+         */
+        private fun createCarrierConfigContext(context: Context, mcc: Int, mnc: Int): Context {
+            // Copy the existing configuration
+            val c = Configuration(context.resources.configuration)
+            c.mcc = mcc
+            c.mnc = mnc
+
+            return ContextThemeWrapper(context, context.theme).also { ctx ->
+                ctx.applyOverrideConfiguration(c)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 8752f92..7cd79ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -18,7 +18,6 @@
 
 import android.app.IActivityManager;
 import android.content.Context;
-import android.os.Handler;
 import android.os.RemoteException;
 import android.service.dreams.IDreamManager;
 import android.util.Log;
@@ -42,14 +41,12 @@
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.RemoteInputNotificationRebuilder;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.commandline.CommandRegistry;
 import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -99,11 +96,8 @@
             NotificationLockscreenUserManager lockscreenUserManager,
             SmartReplyController smartReplyController,
             NotificationVisibilityProvider visibilityProvider,
-            NotificationEntryManager notificationEntryManager,
-            RemoteInputNotificationRebuilder rebuilder,
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             StatusBarStateController statusBarStateController,
-            Handler mainHandler,
             RemoteInputUriController remoteInputUriController,
             NotificationClickNotifier clickNotifier,
             ActionClickLogger actionClickLogger,
@@ -114,7 +108,6 @@
                 lockscreenUserManager,
                 smartReplyController,
                 visibilityProvider,
-                notificationEntryManager,
                 centralSurfacesOptionalLazy,
                 statusBarStateController,
                 remoteInputUriController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
index 66591b3..f04159c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DisableFlagsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableFlagsLogger.kt
@@ -13,23 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.statusbar
+package com.android.systemui.statusbar.disableflags
 
+import android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS
+import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.app.StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS
+import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
 import android.app.StatusBarManager.DISABLE_BACK
 import android.app.StatusBarManager.DISABLE_CLOCK
 import android.app.StatusBarManager.DISABLE_EXPAND
 import android.app.StatusBarManager.DISABLE_HOME
-import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
 import android.app.StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
 import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP
 import android.app.StatusBarManager.DISABLE_RECENT
 import android.app.StatusBarManager.DISABLE_SEARCH
 import android.app.StatusBarManager.DISABLE_SYSTEM_INFO
-import android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS
-import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE
-import android.app.StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS
-import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
-import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
 import com.android.systemui.dagger.SysUISingleton
 import javax.inject.Inject
 
@@ -213,4 +213,4 @@
         DisableFlagsLogger.DisableFlag(DISABLE2_GLOBAL_ACTIONS, 'G', 'g'),
         DisableFlagsLogger.DisableFlag(DISABLE2_ROTATE_SUGGESTIONS, 'R', 'r')
 )
-// LINT.ThenChange(frameworks/base/core/java/android/app/StatusBarManager.java)
\ No newline at end of file
+// LINT.ThenChange(frameworks/base/core/java/android/app/StatusBarManager.java)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableStateTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableStateTracker.kt
new file mode 100644
index 0000000..562f585
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/DisableStateTracker.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.disableflags
+
+import com.android.systemui.statusbar.CommandQueue
+
+/**
+ * Tracks the relevant DISABLE_* flags provided in [mask1] and [mask2] and sets [isDisabled] based
+ * on those masks. [callback] will be notified whenever [isDisabled] changes.
+ *
+ * Users are responsible for adding and removing this tracker from [CommandQueue] callbacks.
+ */
+class DisableStateTracker(
+    private val mask1: Int,
+    private val mask2: Int,
+    private val callback: Callback,
+) : CommandQueue.Callbacks {
+    /**
+     * True if any of the bits in [mask1] or [mask2] are on for the current disable flags, and false
+     * otherwise.
+     */
+    var isDisabled = false
+        private set(value) {
+            if (field == value) return
+            field = value
+            callback.onDisabledChanged()
+        }
+
+    private var displayId: Int? = null
+
+    /** Start tracking the disable flags and updating [isDisabled] accordingly. */
+    fun startTracking(commandQueue: CommandQueue, displayId: Int) {
+        // A view will only have its displayId once it's attached to a window, so we can only
+        // provide the displayId when we start tracking.
+        this.displayId = displayId
+        commandQueue.addCallback(this)
+    }
+
+    /**
+     * Stop tracking the disable flags.
+     *
+     * [isDisabled] will stay at the same value until we start tracking again.
+     */
+    fun stopTracking(commandQueue: CommandQueue) {
+        this.displayId = null
+        commandQueue.removeCallback(this)
+    }
+
+    override fun disable(displayId: Int, state1: Int, state2: Int, animate: Boolean) {
+        if (this.displayId == null || displayId != this.displayId) {
+            return
+        }
+        isDisabled = state1 and mask1 != 0 || state2 and mask2 != 0
+    }
+
+    /** Callback triggered whenever the value of [isDisabled] changes. */
+    fun interface Callback {
+        fun onDisabledChanged()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
index 8cb18a0..59022c0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java
@@ -50,7 +50,6 @@
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.CoreStartable;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -76,20 +75,22 @@
     private final Executor mUiBgExecutor;
     private final ArraySet<Pair<String, Integer>> mCurrentNotifs = new ArraySet<>();
     private final CommandQueue mCommandQueue;
-    private KeyguardStateController mKeyguardStateController;
+    private final KeyguardStateController mKeyguardStateController;
 
     @Inject
-    public InstantAppNotifier(Context context, CommandQueue commandQueue,
-            @UiBackground Executor uiBgExecutor) {
+    public InstantAppNotifier(
+            Context context,
+            CommandQueue commandQueue,
+            @UiBackground Executor uiBgExecutor,
+            KeyguardStateController keyguardStateController) {
         super(context);
         mCommandQueue = commandQueue;
         mUiBgExecutor = uiBgExecutor;
+        mKeyguardStateController = keyguardStateController;
     }
 
     @Override
     public void start() {
-        mKeyguardStateController = Dependency.get(KeyguardStateController.class);
-
         // listen for user / profile change.
         try {
             ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
deleted file mode 100644
index e2f87b6..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.systemui.statusbar.notification;
-
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
-import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * NotificationEntryManager is responsible for the adding, removing, and updating of
- * {@link NotificationEntry}s. It also handles tasks such as their inflation and their interaction
- * with other Notification.*Manager objects.
- *
- * We track notification entries through this lifecycle:
- *      1. Pending
- *      2. Active
- *      3. Sorted / filtered (visible)
- *
- * Every entry spends some amount of time in the pending state, while it is being inflated. Once
- * inflated, an entry moves into the active state, where it _could_ potentially be shown to the
- * user. After an entry makes its way into the active state, we sort and filter the entire set to
- * repopulate the visible set.
- */
-public class NotificationEntryManager implements VisualStabilityManager.Callback {
-
-    private final NotificationEntryManagerLogger mLogger;
-
-    /** Pending notifications are ones awaiting inflation */
-    @VisibleForTesting
-    protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
-    /**
-     * Active notifications have been inflated / prepared and could become visible, but may get
-     * filtered out if for instance they are not for the current user
-     */
-    private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
-    /** This is the list of "active notifications for this user in this context" */
-    @VisibleForTesting
-    protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
-    private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
-    private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
-
-    /**
-     * Injected constructor. See {@link NotificationsModule}.
-     */
-    public NotificationEntryManager(NotificationEntryManagerLogger logger) {
-        mLogger = logger;
-    }
-
-    /** Adds a {@link NotificationEntryListener}. */
-    public void addNotificationEntryListener(NotificationEntryListener listener) {
-        mNotificationEntryListeners.add(listener);
-    }
-
-    /**
-     * Removes a {@link NotificationEntryListener} previously registered via
-     * {@link #addNotificationEntryListener(NotificationEntryListener)}.
-     */
-    public void removeNotificationEntryListener(NotificationEntryListener listener) {
-        mNotificationEntryListeners.remove(listener);
-    }
-
-    @Override
-    public void onChangeAllowed() {
-        updateNotifications("reordering is now allowed");
-    }
-
-    /**
-     * Update the notifications
-     * @param reason why the notifications are updating
-     */
-    public void updateNotifications(String reason) {
-        mLogger.logUseWhileNewPipelineActive("updateNotifications", reason);
-    }
-
-    /*
-     * -----
-     * Annexed from NotificationData below:
-     * Some of these methods may be redundant but require some reworking to remove. For now
-     * we'll try to keep the behavior the same and can simplify these interfaces in another pass
-     */
-
-    /** Resorts / filters the current notification set with the current RankingMap */
-    public void reapplyFilterAndSort(String reason) {
-        mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason);
-    }
-
-    /** dump the current active notification list. Called from CentralSurfaces */
-    public void dump(PrintWriter pw, String indent) {
-        pw.println("NotificationEntryManager (Legacy)");
-        int filteredLen = mSortedAndFiltered.size();
-        pw.print(indent);
-        pw.println("active notifications: " + filteredLen);
-        int active;
-        for (active = 0; active < filteredLen; active++) {
-            NotificationEntry e = mSortedAndFiltered.get(active);
-            dumpEntry(pw, indent, active, e);
-        }
-        synchronized (mActiveNotifications) {
-            int totalLen = mActiveNotifications.size();
-            pw.print(indent);
-            pw.println("inactive notifications: " + (totalLen - active));
-            int inactiveCount = 0;
-            for (int i = 0; i < totalLen; i++) {
-                NotificationEntry entry = mActiveNotifications.valueAt(i);
-                if (!mSortedAndFiltered.contains(entry)) {
-                    dumpEntry(pw, indent, inactiveCount, entry);
-                    inactiveCount++;
-                }
-            }
-        }
-    }
-
-    private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
-        pw.print(indent);
-        pw.println("  [" + i + "] key=" + e.getKey() + " icon=" + e.getIcons().getStatusBarIcon());
-        StatusBarNotification n = e.getSbn();
-        pw.print(indent);
-        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
-                + e.getRanking().getImportance());
-        pw.print(indent);
-        pw.println("      notification=" + n.getNotification());
-    }
-
-    public void addCollectionListener(@NonNull NotifCollectionListener listener) {
-        mNotifCollectionListeners.add(listener);
-    }
-
-    public void removeCollectionListener(@NonNull NotifCollectionListener listener) {
-        mNotifCollectionListeners.remove(listener);
-    }
-
-    /*
-     * End annexation
-     * -----
-     */
-
-
-    /**
-     * Provides access to keyguard state and user settings dependent data.
-     */
-    public interface KeyguardEnvironment {
-        /** true if the device is provisioned (should always be true in practice) */
-        boolean isDeviceProvisioned();
-        /** true if the notification is for the current profiles */
-        boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
-    }
-
-    /**
-     * Used when a notification is removed and it doesn't have a reason that maps to one of the
-     * reasons defined in NotificationListenerService
-     * (e.g. {@link NotificationListenerService#REASON_CANCEL})
-     */
-    public static final int UNDEFINED_DISMISS_REASON = 0;
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
deleted file mode 100644
index 52dcf02..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManagerLogger.kt
+++ /dev/null
@@ -1,124 +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.statusbar.notification
-
-import com.android.systemui.log.LogBuffer
-import com.android.systemui.log.LogLevel
-import com.android.systemui.log.LogLevel.DEBUG
-import com.android.systemui.log.LogLevel.INFO
-import com.android.systemui.log.LogLevel.WARNING
-import com.android.systemui.log.LogMessage
-import com.android.systemui.log.dagger.NotificationLog
-import com.android.systemui.util.Compile
-import javax.inject.Inject
-
-/** Logger for [NotificationEntryManager]. */
-class NotificationEntryManagerLogger @Inject constructor(
-    notifPipelineFlags: NotifPipelineFlags,
-    @NotificationLog private val buffer: LogBuffer
-) {
-    private val devLoggingEnabled by lazy { notifPipelineFlags.isDevLoggingEnabled() }
-
-    private inline fun devLog(
-        level: LogLevel,
-        initializer: LogMessage.() -> Unit,
-        noinline printer: LogMessage.() -> String
-    ) {
-        if (Compile.IS_DEBUG && devLoggingEnabled) buffer.log(TAG, level, initializer, printer)
-    }
-
-    fun logNotifAdded(key: String) {
-        devLog(INFO, {
-            str1 = key
-        }, {
-            "NOTIF ADDED $str1"
-        })
-    }
-
-    fun logNotifUpdated(key: String) {
-        devLog(INFO, {
-            str1 = key
-        }, {
-            "NOTIF UPDATED $str1"
-        })
-    }
-
-    fun logInflationAborted(key: String, status: String, reason: String) {
-        devLog(DEBUG, {
-            str1 = key
-            str2 = status
-            str3 = reason
-        }, {
-            "NOTIF INFLATION ABORTED $str1 notifStatus=$str2 reason=$str3"
-        })
-    }
-
-    fun logNotifInflated(key: String, isNew: Boolean) {
-        devLog(DEBUG, {
-            str1 = key
-            bool1 = isNew
-        }, {
-            "NOTIF INFLATED $str1 isNew=$bool1}"
-        })
-    }
-
-    fun logRemovalIntercepted(key: String) {
-        devLog(INFO, {
-            str1 = key
-        }, {
-            "NOTIF REMOVE INTERCEPTED for $str1"
-        })
-    }
-
-    fun logLifetimeExtended(key: String, extenderName: String, status: String) {
-        devLog(INFO, {
-            str1 = key
-            str2 = extenderName
-            str3 = status
-        }, {
-            "NOTIF LIFETIME EXTENDED $str1 extender=$str2 status=$str3"
-        })
-    }
-
-    fun logNotifRemoved(key: String, removedByUser: Boolean) {
-        devLog(INFO, {
-            str1 = key
-            bool1 = removedByUser
-        }, {
-            "NOTIF REMOVED $str1 removedByUser=$bool1"
-        })
-    }
-
-    fun logFilterAndSort(reason: String) {
-        devLog(INFO, {
-            str1 = reason
-        }, {
-            "FILTER AND SORT reason=$str1"
-        })
-    }
-
-    fun logUseWhileNewPipelineActive(method: String, reason: String) {
-        buffer.log(TAG, WARNING, {
-            str1 = method
-            str2 = reason
-        }, {
-            "While running New Pipeline: $str1(reason=$str2)"
-        })
-    }
-}
-
-private const val TAG = "NotificationEntryMgr"
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
deleted file mode 100644
index c9c6f28..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationListController.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification;
-
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-
-import java.util.Objects;
-
-/**
- * Root controller for the list of notifications in the shade.
- *
- * TODO: Much of the code in NotificationPresenter should eventually move in here. It will proxy
- * domain-specific behavior (ARC, etc) to subcontrollers.
- */
-public class NotificationListController {
-    private final NotificationEntryManager mEntryManager;
-    private final NotificationListContainer mListContainer;
-    private final DeviceProvisionedController mDeviceProvisionedController;
-
-    public NotificationListController(
-            NotificationEntryManager entryManager,
-            NotificationListContainer listContainer,
-            DeviceProvisionedController deviceProvisionedController) {
-        mEntryManager = Objects.requireNonNull(entryManager);
-        mListContainer = Objects.requireNonNull(listContainer);
-        mDeviceProvisionedController = Objects.requireNonNull(deviceProvisionedController);
-    }
-
-    /**
-     * Causes the controller to register listeners on its dependencies. This method must be called
-     * before the controller is ready to perform its duties.
-     */
-    public void bind() {
-        mEntryManager.addNotificationEntryListener(mEntryListener);
-        mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
-    }
-
-    @SuppressWarnings("FieldCanBeLocal")
-    private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
-        @Override
-        public void onEntryRemoved(
-                NotificationEntry entry,
-                NotificationVisibility visibility,
-                boolean removedByUser,
-                int reason) {
-            mListContainer.cleanUpViewStateForEntry(entry);
-        }
-    };
-
-    // TODO: (b/145659174) remove after moving to NewNotifPipeline. Replaced by
-    //  DeviceProvisionedCoordinator
-    private final DeviceProvisionedListener mDeviceProvisionedListener =
-            new DeviceProvisionedListener() {
-                @Override
-                public void onDeviceProvisionedChanged() {
-                    mEntryManager.updateNotifications("device provisioned changed");
-                }
-            };
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index dbf4810..126a986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -18,10 +18,8 @@
 
 import android.animation.ObjectAnimator
 import android.util.FloatProperty
-import com.android.systemui.Dumpable
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -34,20 +32,17 @@
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener
 import com.android.systemui.statusbar.policy.HeadsUpManager
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
-import java.io.PrintWriter
 import javax.inject.Inject
 import kotlin.math.min
 
 @SysUISingleton
 class NotificationWakeUpCoordinator @Inject constructor(
-    dumpManager: DumpManager,
     private val mHeadsUpManager: HeadsUpManager,
     private val statusBarStateController: StatusBarStateController,
     private val bypassController: KeyguardBypassController,
     private val dozeParameters: DozeParameters,
     private val screenOffAnimationController: ScreenOffAnimationController
-) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener,
-    Dumpable {
+) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener {
 
     private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>(
         "notificationVisibility") {
@@ -65,7 +60,6 @@
 
     private var mLinearDozeAmount: Float = 0.0f
     private var mDozeAmount: Float = 0.0f
-    private var mDozeAmountSource: String = "init"
     private var mNotificationVisibleAmount = 0.0f
     private var mNotificationsVisible = false
     private var mNotificationsVisibleForExpansion = false
@@ -148,7 +142,6 @@
         }
 
     init {
-        dumpManager.registerDumpable(this)
         mHeadsUpManager.addListener(this)
         statusBarStateController.addCallback(this)
         addListener(object : WakeUpListener {
@@ -255,14 +248,13 @@
             // Let's notify the scroller that an animation started
             notifyAnimationStart(mLinearDozeAmount == 1.0f)
         }
-        setDozeAmount(linear, eased, source = "StatusBar")
+        setDozeAmount(linear, eased)
     }
 
-    fun setDozeAmount(linear: Float, eased: Float, source: String) {
+    fun setDozeAmount(linear: Float, eased: Float) {
         val changed = linear != mLinearDozeAmount
         mLinearDozeAmount = linear
         mDozeAmount = eased
-        mDozeAmountSource = source
         mStackScrollerController.setDozeAmount(mDozeAmount)
         updateHideAmount()
         if (changed && linear == 0.0f) {
@@ -279,7 +271,7 @@
             // undefined state, so it's an indication that we should do state cleanup. We override
             // the doze amount to 0f (not dozing) so that the notifications are no longer hidden.
             // See: UnlockedScreenOffAnimationController.onFinishedWakingUp()
-            setDozeAmount(0f, 0f, source = "Override: Shade->Shade (lock cancelled by unlock)")
+            setDozeAmount(0f, 0f)
         }
 
         if (overrideDozeAmountIfAnimatingScreenOff(mLinearDozeAmount)) {
@@ -319,11 +311,12 @@
      */
     private fun overrideDozeAmountIfBypass(): Boolean {
         if (bypassController.bypassEnabled) {
-            if (statusBarStateController.state == StatusBarState.KEYGUARD) {
-                setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)")
-            } else {
-                setDozeAmount(0f, 0f, source = "Override: bypass (shade)")
+            var amount = 1.0f
+            if (statusBarStateController.state == StatusBarState.SHADE ||
+                statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
+                amount = 0.0f
             }
+            setDozeAmount(amount, amount)
             return true
         }
         return false
@@ -339,7 +332,7 @@
      */
     private fun overrideDozeAmountIfAnimatingScreenOff(linearDozeAmount: Float): Boolean {
         if (screenOffAnimationController.overrideNotificationsFullyDozingOnKeyguard()) {
-            setDozeAmount(1f, 1f, source = "Override: animating screen off")
+            setDozeAmount(1f, 1f)
             return true
         }
 
@@ -433,24 +426,4 @@
          */
         @JvmDefault fun onPulseExpansionChanged(expandingChanged: Boolean) {}
     }
-
-    override fun dump(pw: PrintWriter, args: Array<out String>) {
-        pw.println("mLinearDozeAmount: $mLinearDozeAmount")
-        pw.println("mDozeAmount: $mDozeAmount")
-        pw.println("mDozeAmountSource: $mDozeAmountSource")
-        pw.println("mNotificationVisibleAmount: $mNotificationVisibleAmount")
-        pw.println("mNotificationsVisible: $mNotificationsVisible")
-        pw.println("mNotificationsVisibleForExpansion: $mNotificationsVisibleForExpansion")
-        pw.println("mVisibilityAmount: $mVisibilityAmount")
-        pw.println("mLinearVisibilityAmount: $mLinearVisibilityAmount")
-        pw.println("pulseExpanding: $pulseExpanding")
-        pw.println("state: ${StatusBarState.toString(state)}")
-        pw.println("fullyAwake: $fullyAwake")
-        pw.println("wakingUp: $wakingUp")
-        pw.println("willWakeUp: $willWakeUp")
-        pw.println("collapsedEnoughToHide: $collapsedEnoughToHide")
-        pw.println("pulsing: $pulsing")
-        pw.println("notificationsFullyHidden: $notificationsFullyHidden")
-        pw.println("canShowPulsingHuns: $canShowPulsingHuns")
-    }
-}
+}
\ No newline at end of file
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/collection/coordinator/SmartspaceDedupingCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
index 9d0f974..32150fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinator.kt
@@ -20,11 +20,9 @@
 import android.os.Parcelable
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
-import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
@@ -44,14 +42,10 @@
  * In addition, notifications that have recently alerted aren't filtered. Tracking this in a way
  * that involves the fewest pipeline invalidations requires some unfortunately complex logic.
  */
-// This class is a singleton so that the same instance can be accessed by both the old and new
-// pipelines
 @CoordinatorScope
 class SmartspaceDedupingCoordinator @Inject constructor(
     private val statusBarStateController: SysuiStatusBarStateController,
     private val smartspaceController: LockscreenSmartspaceController,
-    private val notificationEntryManager: NotificationEntryManager,
-    private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
     private val notifPipeline: NotifPipeline,
     @Main private val executor: DelayableExecutor,
     private val clock: SystemClock
@@ -132,7 +126,6 @@
 
         if (changed) {
             filter.invalidateList("onNewSmartspaceTargets")
-            notificationEntryManager.updateNotifications("Smartspace targets changed")
         }
 
         trackedSmartspaceTargets = newMap
@@ -169,7 +162,6 @@
                 target.cancelTimeoutRunnable = null
                 target.shouldFilter = true
                 filter.invalidateList("updateAlertException: ${entry.logKey}")
-                notificationEntryManager.updateNotifications("deduping timeout expired")
             }, alertExceptionExpires - now)
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
index 46b467e..cdfd2f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
@@ -16,16 +16,14 @@
 
 package com.android.systemui.statusbar.notification.collection.inflation;
 
-import android.annotation.Nullable;
+import android.annotation.NonNull;
 
-import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
 
 /**
- * Used by the {@link NotificationEntryManager}. When notifications are added or updated, the binder
+ * Used by the {@link NotifInflater}. When notifications are added or updated, the binder
  * is asked to (re)inflate and prepare their views. This inflation must occur off the main thread.
  */
 public interface NotificationRowBinder {
@@ -35,23 +33,11 @@
      */
     void inflateViews(
             NotificationEntry entry,
-            NotifInflater.Params params,
+            @NonNull NotifInflater.Params params,
             NotificationRowContentBinder.InflationCallback callback)
             throws InflationException;
 
     /**
-     * Called when the ranking has been updated (but not add or remove has been done). The binder
-     * should inspect the old and new adjustments and re-inflate the entry's views if necessary
-     * (e.g. if something important changed).
-     */
-    void onNotificationRankingUpdated(
-            NotificationEntry entry,
-            @Nullable Integer oldImportance,
-            NotificationUiAdjustment oldAdjustment,
-            NotificationUiAdjustment newAdjustment,
-            NotificationRowContentBinder.InflationCallback callback);
-
-    /**
      * Called when a notification is no longer likely to be displayed and can have its views freed.
      */
     void releaseViews(NotificationEntry entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 528f720..47cdde4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -22,6 +22,7 @@
 
 import static java.util.Objects.requireNonNull;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.os.Build;
@@ -32,12 +33,9 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationClicker;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.legacy.LowPriorityInflationHelper;
 import com.android.systemui.statusbar.notification.icon.IconManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
@@ -68,8 +66,6 @@
     private final ExpandableNotificationRowComponent.Builder
             mExpandableNotificationRowComponentBuilder;
     private final IconManager mIconManager;
-    private final LowPriorityInflationHelper mLowPriorityInflationHelper;
-    private final NotifPipelineFlags mNotifPipelineFlags;
 
     private NotificationPresenter mPresenter;
     private NotificationListContainer mListContainer;
@@ -86,9 +82,7 @@
             RowContentBindStage rowContentBindStage,
             Provider<RowInflaterTask> rowInflaterTaskProvider,
             ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
-            IconManager iconManager,
-            LowPriorityInflationHelper lowPriorityInflationHelper,
-            NotifPipelineFlags notifPipelineFlags) {
+            IconManager iconManager) {
         mContext = context;
         mNotifBindPipeline = notifBindPipeline;
         mRowContentBindStage = rowContentBindStage;
@@ -98,8 +92,6 @@
         mRowInflaterTaskProvider = rowInflaterTaskProvider;
         mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
         mIconManager = iconManager;
-        mLowPriorityInflationHelper = lowPriorityInflationHelper;
-        mNotifPipelineFlags = notifPipelineFlags;
     }
 
     /**
@@ -125,13 +117,9 @@
     @Override
     public void inflateViews(
             NotificationEntry entry,
-            NotifInflater.Params params,
+            @NonNull NotifInflater.Params params,
             NotificationRowContentBinder.InflationCallback callback)
             throws InflationException {
-        if (params == null) {
-            // weak assert that the params should always be passed in the new pipeline
-            mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        }
         ViewGroup parent = mListContainer.getViewParentForNotification(entry);
 
         if (entry.rowExists()) {
@@ -191,39 +179,6 @@
     }
 
     /**
-     * Updates the views bound to an entry when the entry's ranking changes, either in-place or by
-     * reinflating them.
-     *
-     * TODO: Should this method be in this class?
-     */
-    @Override
-    public void onNotificationRankingUpdated(
-            NotificationEntry entry,
-            @Nullable Integer oldImportance,
-            NotificationUiAdjustment oldAdjustment,
-            NotificationUiAdjustment newAdjustment,
-            NotificationRowContentBinder.InflationCallback callback) {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        if (NotificationUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) {
-            if (entry.rowExists()) {
-                ExpandableNotificationRow row = entry.getRow();
-                row.reset();
-                updateRow(entry, row);
-                inflateContentViews(entry, null, row, callback);
-            } else {
-                // Once the RowInflaterTask is done, it will pick up the updated entry, so
-                // no-op here.
-            }
-        } else {
-            if (oldImportance != null && entry.getImportance() != oldImportance) {
-                if (entry.rowExists()) {
-                    entry.getRow().onNotificationRankingUpdated();
-                }
-            }
-        }
-    }
-
-    /**
      * Update row after the notification has updated.
      *
      * @param entry notification that has updated
@@ -243,24 +198,12 @@
      */
     private void inflateContentViews(
             NotificationEntry entry,
-            NotifInflater.Params inflaterParams,
+            @NonNull NotifInflater.Params inflaterParams,
             ExpandableNotificationRow row,
             @Nullable NotificationRowContentBinder.InflationCallback inflationCallback) {
         final boolean useIncreasedCollapsedHeight =
                 mMessagingUtil.isImportantMessaging(entry.getSbn(), entry.getImportance());
-        final boolean isLowPriority;
-        if (inflaterParams != null) {
-            // NEW pipeline
-            isLowPriority = inflaterParams.isLowPriority();
-        } else {
-            // LEGACY pipeline
-            mNotifPipelineFlags.checkLegacyPipelineEnabled();
-            // If this is our first time inflating, we don't actually know the groupings for real
-            // yet, so we might actually inflate a low priority content view incorrectly here and
-            // have to correct it later in the pipeline. On subsequent inflations (i.e. updates),
-            // this should inflate the correct view.
-            isLowPriority = mLowPriorityInflationHelper.shouldUseLowPriorityView(entry);
-        }
+        final boolean isLowPriority = inflaterParams.isLowPriority();
 
         RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
         params.requireContentViews(FLAG_CONTENT_VIEW_CONTRACTED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java
deleted file mode 100644
index 89445a5..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/LowPriorityInflationHelper.java
+++ /dev/null
@@ -1,49 +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.statusbar.notification.collection.legacy;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-import javax.inject.Inject;
-
-/**
- * Helper class that provide methods to help check when we need to inflate a low priority version
- * ot notification content.
- */
-@SysUISingleton
-public class LowPriorityInflationHelper {
-    private final NotificationGroupManagerLegacy mGroupManager;
-    private final NotifPipelineFlags mNotifPipelineFlags;
-
-    @Inject
-    LowPriorityInflationHelper(
-            NotificationGroupManagerLegacy groupManager,
-            NotifPipelineFlags notifPipelineFlags) {
-        mGroupManager = groupManager;
-        mNotifPipelineFlags = notifPipelineFlags;
-    }
-
-    /**
-     * Whether the notification should inflate a low priority version of its content views.
-     */
-    public boolean shouldUseLowPriorityView(NotificationEntry entry) {
-        mNotifPipelineFlags.checkLegacyPipelineEnabled();
-        return entry.isAmbient() && !mGroupManager.isChildInGroup(entry);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
deleted file mode 100644
index d41f6fe..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ /dev/null
@@ -1,950 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.legacy;
-
-import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Notification;
-import android.service.notification.StatusBarNotification;
-import android.util.ArraySet;
-import android.util.Log;
-
-import com.android.systemui.Dumpable;
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.util.Compile;
-import com.android.wm.shell.bubbles.Bubbles;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.TreeSet;
-import java.util.function.Function;
-
-import javax.inject.Inject;
-
-import dagger.Lazy;
-
-/**
- * A class to handle notifications and their corresponding groups.
- * This includes:
- * 1. Determining whether an entry is a member of a group and whether it is a summary or a child
- * 2. Tracking group expansion states
- */
-@SysUISingleton
-public class NotificationGroupManagerLegacy implements StateListener, Dumpable {
-
-    private static final String TAG = "LegacyNotifGroupManager";
-    private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean SPEW = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.VERBOSE);
-    /**
-     * The maximum amount of time (in ms) between the posting of notifications that can be
-     * considered part of the same update batch.
-     */
-    private static final long POST_BATCH_MAX_AGE = 5000;
-    private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
-    private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
-    private final Optional<Bubbles> mBubblesOptional;
-    private final GroupEventDispatcher mEventDispatcher = new GroupEventDispatcher(mGroupMap::get);
-    private final HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
-    private boolean mIsUpdatingUnchangedGroup;
-
-    @Inject
-    public NotificationGroupManagerLegacy(
-            StatusBarStateController statusBarStateController,
-            Lazy<PeopleNotificationIdentifier> peopleNotificationIdentifier,
-            Optional<Bubbles> bubblesOptional,
-            DumpManager dumpManager) {
-        statusBarStateController.addCallback(this);
-        mPeopleNotificationIdentifier = peopleNotificationIdentifier;
-        mBubblesOptional = bubblesOptional;
-
-        dumpManager.registerDumpable(this);
-    }
-
-    /**
-     * Add a listener for changes to groups.
-     */
-    public void registerGroupChangeListener(OnGroupChangeListener listener) {
-        mEventDispatcher.registerGroupChangeListener(listener);
-    }
-
-    private void setGroupExpanded(NotificationGroup group, boolean expanded) {
-        group.expanded = expanded;
-    }
-
-    /**
-     * When we want to remove an entry from being tracked for grouping
-     */
-    public void onEntryRemoved(NotificationEntry removed) {
-        if (SPEW) {
-            Log.d(TAG, "onEntryRemoved: entry=" + logKey(removed));
-        }
-        mEventDispatcher.openBufferScope();
-        onEntryRemovedInternal(removed, removed.getSbn());
-        StatusBarNotification oldSbn = mIsolatedEntries.remove(removed.getKey());
-        if (oldSbn != null) {
-            updateSuppression(mGroupMap.get(oldSbn.getGroupKey()));
-        }
-        mEventDispatcher.closeBufferScope();
-    }
-
-    /**
-     * An entry was removed.
-     *
-     * @param removed the removed entry
-     * @param sbn the notification the entry has, which doesn't need to be the same as it's internal
-     *            notification
-     */
-    private void onEntryRemovedInternal(NotificationEntry removed,
-            final StatusBarNotification sbn) {
-        onEntryRemovedInternal(removed, sbn.getGroupKey(), sbn.isGroup(),
-                sbn.getNotification().isGroupSummary());
-    }
-
-    private void onEntryRemovedInternal(NotificationEntry removed, String notifGroupKey, boolean
-            isGroup, boolean isGroupSummary) {
-        String groupKey = getGroupKey(removed.getKey(), notifGroupKey);
-        final NotificationGroup group = mGroupMap.get(groupKey);
-        if (group == null) {
-            // When an app posts 2 different notifications as summary of the same group, then a
-            // cancellation of the first notification removes this group.
-            // This situation is not supported and we will not allow such notifications anymore in
-            // the close future. See b/23676310 for reference.
-            return;
-        }
-        if (SPEW) {
-            Log.d(TAG, "onEntryRemovedInternal: entry=" + logKey(removed)
-                    + " group=" + logGroupKey(group));
-        }
-        if (isGroupChild(removed.getKey(), isGroup, isGroupSummary)) {
-            group.children.remove(removed.getKey());
-        } else {
-            group.summary = null;
-        }
-        updateSuppression(group);
-        if (group.children.isEmpty()) {
-            if (group.summary == null) {
-                mGroupMap.remove(groupKey);
-                mEventDispatcher.notifyGroupRemoved(group);
-            }
-        }
-    }
-
-    private void onEntryAddedInternal(final NotificationEntry added) {
-        if (added.isRowRemoved()) {
-            added.setDebugThrowable(new Throwable());
-        }
-        final StatusBarNotification sbn = added.getSbn();
-        boolean isGroupChild = isGroupChild(sbn);
-        String groupKey = getGroupKey(sbn);
-        NotificationGroup group = mGroupMap.get(groupKey);
-        if (group == null) {
-            group = new NotificationGroup(groupKey);
-            mGroupMap.put(groupKey, group);
-            mEventDispatcher.notifyGroupCreated(group);
-        }
-        if (SPEW) {
-            Log.d(TAG, "onEntryAddedInternal: entry=" + logKey(added)
-                    + " group=" + logGroupKey(group));
-        }
-        if (isGroupChild) {
-            NotificationEntry existing = group.children.get(added.getKey());
-            if (existing != null && existing != added) {
-                Throwable existingThrowable = existing.getDebugThrowable();
-                Log.wtf(TAG, "Inconsistent entries found with the same key " + logKey(added)
-                        + "existing removed: " + existing.isRowRemoved()
-                        + (existingThrowable != null
-                                ? Log.getStackTraceString(existingThrowable) + "\n" : "")
-                        + " added removed" + added.isRowRemoved(), new Throwable());
-            }
-            group.children.put(added.getKey(), added);
-            addToPostBatchHistory(group, added);
-            updateSuppression(group);
-        } else {
-            group.summary = added;
-            addToPostBatchHistory(group, added);
-            group.expanded = added.areChildrenExpanded();
-            updateSuppression(group);
-            if (!group.children.isEmpty()) {
-                ArrayList<NotificationEntry> childrenCopy =
-                        new ArrayList<>(group.children.values());
-                for (NotificationEntry child : childrenCopy) {
-                    onEntryBecomingChild(child);
-                }
-                mEventDispatcher.notifyGroupsChanged();
-            }
-        }
-    }
-
-    private void addToPostBatchHistory(NotificationGroup group, @Nullable NotificationEntry entry) {
-        if (entry == null) {
-            return;
-        }
-        boolean didAdd = group.postBatchHistory.add(new PostRecord(entry));
-        if (didAdd) {
-            trimPostBatchHistory(group.postBatchHistory);
-        }
-    }
-
-    /** remove all history that's too old to be in the batch. */
-    private void trimPostBatchHistory(@NonNull TreeSet<PostRecord> postBatchHistory) {
-        if (postBatchHistory.size() <= 1) {
-            return;
-        }
-        long batchStartTime = postBatchHistory.last().postTime - POST_BATCH_MAX_AGE;
-        while (!postBatchHistory.isEmpty() && postBatchHistory.first().postTime < batchStartTime) {
-            postBatchHistory.pollFirst();
-        }
-    }
-
-    private void onEntryBecomingChild(NotificationEntry entry) {
-        updateIsolation(entry);
-    }
-
-    private void updateSuppression(NotificationGroup group) {
-        if (group == null) {
-            return;
-        }
-        NotificationEntry prevAlertOverride = group.alertOverride;
-        group.alertOverride = getPriorityConversationAlertOverride(group);
-
-        int childCount = 0;
-        boolean hasBubbles = false;
-        for (NotificationEntry entry : group.children.values()) {
-            if (mBubblesOptional.isPresent() && mBubblesOptional.get()
-                    .isBubbleNotificationSuppressedFromShade(
-                            entry.getKey(), entry.getSbn().getGroupKey())) {
-                hasBubbles = true;
-            } else {
-                childCount++;
-            }
-        }
-
-        boolean prevSuppressed = group.suppressed;
-        group.suppressed = group.summary != null && !group.expanded
-                && (childCount == 1
-                || (childCount == 0
-                && group.summary.getSbn().getNotification().isGroupSummary()
-                && (hasIsolatedChildren(group) || hasBubbles)));
-
-        boolean alertOverrideChanged = prevAlertOverride != group.alertOverride;
-        boolean suppressionChanged = prevSuppressed != group.suppressed;
-        if (alertOverrideChanged || suppressionChanged) {
-            if (DEBUG) {
-                Log.d(TAG, "updateSuppression:"
-                        + " willNotifyListeners=" + !mIsUpdatingUnchangedGroup
-                        + " changes for group:\n" + group);
-                if (alertOverrideChanged) {
-                    Log.d(TAG, "updateSuppression: alertOverride was=" + logKey(prevAlertOverride)
-                            + " now=" + logKey(group.alertOverride));
-                }
-                if (suppressionChanged) {
-                    Log.d(TAG, "updateSuppression: suppressed changed to " + group.suppressed);
-                }
-            }
-            if (alertOverrideChanged) {
-                mEventDispatcher.notifyAlertOverrideChanged(group, prevAlertOverride);
-            }
-            if (suppressionChanged) {
-                mEventDispatcher.notifySuppressedChanged(group);
-            }
-            if (!mIsUpdatingUnchangedGroup) {
-                mEventDispatcher.notifyGroupsChanged();
-            }
-        }
-    }
-
-    /**
-     * Finds the isolated logical child of this group which is should be alerted instead.
-     *
-     * Notifications from priority conversations are isolated from their groups to make them more
-     * prominent, however apps may post these with a GroupAlertBehavior that has the group receiving
-     * the alert.  This would lead to the group alerting even though the conversation that was
-     * updated was not actually a part of that group.  This method finds the best priority
-     * conversation in this situation, if there is one, so they can be set as the alertOverride of
-     * the group.
-     *
-     * @param group the group to check
-     * @return the entry which should receive the alert instead of the group, if any.
-     */
-    @Nullable
-    private NotificationEntry getPriorityConversationAlertOverride(NotificationGroup group) {
-        // GOAL: if there is a priority child which wouldn't alert based on its groupAlertBehavior,
-        // but which should be alerting (because priority conversations are isolated), find it.
-        if (group == null || group.summary == null) {
-            if (SPEW) {
-                Log.d(TAG, "getPriorityConversationAlertOverride: null group or summary"
-                        + " group=" + logGroupKey(group));
-            }
-            return null;
-        }
-        if (isIsolated(group.summary.getKey())) {
-            if (SPEW) {
-                Log.d(TAG, "getPriorityConversationAlertOverride: isolated group"
-                        + " group=" + logGroupKey(group));
-            }
-            return null;
-        }
-
-        // Precondiions:
-        // * Only necessary when all notifications in the group use GROUP_ALERT_SUMMARY
-        // * Only necessary when at least one notification in the group is on a priority channel
-        if (group.summary.getSbn().getNotification().getGroupAlertBehavior()
-                == Notification.GROUP_ALERT_CHILDREN) {
-            if (SPEW) {
-                Log.d(TAG, "getPriorityConversationAlertOverride: summary == GROUP_ALERT_CHILDREN"
-                        + " group=" + logGroupKey(group));
-            }
-            return null;
-        }
-
-        // Get the important children first, copy the keys for the final importance check,
-        // then add the non-isolated children to the map for unified lookup.
-        HashMap<String, NotificationEntry> children = getImportantConversations(group);
-        if (children == null || children.isEmpty()) {
-            if (SPEW) {
-                Log.d(TAG, "getPriorityConversationAlertOverride: no important conversations"
-                        + " group=" + logGroupKey(group));
-            }
-            return null;
-        }
-        HashSet<String> importantChildKeys = new HashSet<>(children.keySet());
-        children.putAll(group.children);
-
-        // Ensure all children have GROUP_ALERT_SUMMARY
-        for (NotificationEntry child : children.values()) {
-            if (child.getSbn().getNotification().getGroupAlertBehavior()
-                    != Notification.GROUP_ALERT_SUMMARY) {
-                if (SPEW) {
-                    Log.d(TAG, "getPriorityConversationAlertOverride: child != GROUP_ALERT_SUMMARY"
-                            + " group=" + logGroupKey(group));
-                }
-                return null;
-            }
-        }
-
-        // Create a merged post history from all the children
-        TreeSet<PostRecord> combinedHistory = new TreeSet<>(group.postBatchHistory);
-        for (String importantChildKey : importantChildKeys) {
-            NotificationGroup importantChildGroup = mGroupMap.get(importantChildKey);
-            combinedHistory.addAll(importantChildGroup.postBatchHistory);
-        }
-        trimPostBatchHistory(combinedHistory);
-
-        // This is a streamlined implementation of the following idea:
-        // * From the subset of notifications in the latest 'batch' of updates.  A batch is:
-        //   * Notifs posted less than POST_BATCH_MAX_AGE before the most recently posted.
-        //   * Only including notifs newer than the second-to-last post of any notification.
-        // * Find the newest child in the batch -- the with the largest 'when' value.
-        // * If the newest child is a priority conversation, set that as the override.
-        HashSet<String> batchKeys = new HashSet<>();
-        long newestChildWhen = -1;
-        NotificationEntry newestChild = null;
-        // Iterate backwards through the post history, tracking the child with the smallest sort key
-        for (PostRecord record : combinedHistory.descendingSet()) {
-            if (batchKeys.contains(record.key)) {
-                // Once you see a notification again, the batch has ended
-                break;
-            }
-            batchKeys.add(record.key);
-            NotificationEntry child = children.get(record.key);
-            if (child != null) {
-                long childWhen = child.getSbn().getNotification().when;
-                if (newestChild == null || childWhen > newestChildWhen) {
-                    newestChildWhen = childWhen;
-                    newestChild = child;
-                }
-            }
-        }
-        if (newestChild != null && importantChildKeys.contains(newestChild.getKey())) {
-            if (SPEW) {
-                Log.d(TAG, "getPriorityConversationAlertOverride:"
-                        + " result=" + logKey(newestChild)
-                        + " group=" + logGroupKey(group));
-            }
-            return newestChild;
-        }
-        if (SPEW) {
-            Log.d(TAG, "getPriorityConversationAlertOverride:"
-                    + " result=null newestChild=" + logKey(newestChild)
-                    + " group=" + logGroupKey(group));
-        }
-        return null;
-    }
-
-    private boolean hasIsolatedChildren(NotificationGroup group) {
-        return getNumberOfIsolatedChildren(group.summary.getSbn().getGroupKey()) != 0;
-    }
-
-    private int getNumberOfIsolatedChildren(String groupKey) {
-        int count = 0;
-        for (StatusBarNotification sbn : mIsolatedEntries.values()) {
-            if (sbn.getGroupKey().equals(groupKey) && isIsolated(sbn.getKey())) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    @Nullable
-    private HashMap<String, NotificationEntry> getImportantConversations(NotificationGroup group) {
-        String groupKey = group.summary.getSbn().getGroupKey();
-        HashMap<String, NotificationEntry> result = null;
-        for (StatusBarNotification sbn : mIsolatedEntries.values()) {
-            if (sbn.getGroupKey().equals(groupKey)) {
-                NotificationEntry entry = mGroupMap.get(sbn.getKey()).summary;
-                if (isImportantConversation(entry)) {
-                    if (result == null) {
-                        result = new HashMap<>();
-                    }
-                    result.put(sbn.getKey(), entry);
-                }
-            }
-        }
-        return result;
-    }
-
-    private void setStatusBarState(int newState) {
-        if (newState == StatusBarState.KEYGUARD) {
-            collapseGroups();
-        }
-    }
-
-    private void collapseGroups() {
-        // Because notifications can become isolated when the group becomes suppressed it can
-        // lead to concurrent modifications while looping. We need to make a copy.
-        ArrayList<NotificationGroup> groupCopy = new ArrayList<>(mGroupMap.values());
-        int size = groupCopy.size();
-        for (int i = 0; i < size; i++) {
-            NotificationGroup group =  groupCopy.get(i);
-            if (group.expanded) {
-                setGroupExpanded(group, false);
-            }
-            updateSuppression(group);
-        }
-    }
-
-    public boolean isChildInGroup(NotificationEntry entry) {
-        final StatusBarNotification sbn = entry.getSbn();
-        if (!isGroupChild(sbn)) {
-            return false;
-        }
-        NotificationGroup group = mGroupMap.get(getGroupKey(sbn));
-        if (group == null || group.summary == null || group.suppressed) {
-            return false;
-        }
-        if (group.children.isEmpty()) {
-            // If the suppression of a group changes because the last child was removed, this can
-            // still be called temporarily because the child hasn't been fully removed yet. Let's
-            // make sure we still return false in that case.
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * If there is a {@link NotificationGroup} associated with the provided entry, this method
-     * will update the suppression of that group.
-     */
-    public void updateSuppression(NotificationEntry entry) {
-        NotificationGroup group = mGroupMap.get(getGroupKey(entry.getSbn()));
-        if (group != null) {
-            updateSuppression(group);
-        }
-    }
-
-    /**
-     * Get the group key. May differ from the one in the notification due to the notification
-     * being temporarily isolated.
-     *
-     * @param sbn notification to check
-     * @return the key of the notification
-     */
-    private String getGroupKey(StatusBarNotification sbn) {
-        return getGroupKey(sbn.getKey(), sbn.getGroupKey());
-    }
-
-    private String getGroupKey(String key, String groupKey) {
-        if (isIsolated(key)) {
-            return key;
-        }
-        return groupKey;
-    }
-
-    private boolean isIsolated(String sbnKey) {
-        return mIsolatedEntries.containsKey(sbnKey);
-    }
-
-    /**
-     * Whether a notification is visually a group child.
-     *
-     * @param sbn notification to check
-     * @return true if it is visually a group child
-     */
-    private boolean isGroupChild(StatusBarNotification sbn) {
-        return isGroupChild(sbn.getKey(), sbn.isGroup(), sbn.getNotification().isGroupSummary());
-    }
-
-    private boolean isGroupChild(String key, boolean isGroup, boolean isGroupSummary) {
-        if (isIsolated(key)) {
-            return false;
-        }
-        return isGroup && !isGroupSummary;
-    }
-
-    /**
-     * Whether a notification that is normally part of a group should be temporarily isolated from
-     * the group and put in their own group visually.  This generally happens when the notification
-     * is alerting.
-     *
-     * @param entry the notification to check
-     * @return true if the entry should be isolated
-     */
-    private boolean shouldIsolate(NotificationEntry entry) {
-        StatusBarNotification sbn = entry.getSbn();
-        if (!sbn.isGroup() || sbn.getNotification().isGroupSummary()) {
-            return false;
-        }
-        if (isImportantConversation(entry)) {
-            return true;
-        }
-        NotificationGroup notificationGroup = mGroupMap.get(sbn.getGroupKey());
-        return (sbn.getNotification().fullScreenIntent != null
-                    || notificationGroup == null
-                    || !notificationGroup.expanded
-                    || isGroupNotFullyVisible(notificationGroup));
-    }
-
-    private boolean isImportantConversation(NotificationEntry entry) {
-        int peopleNotificationType =
-                mPeopleNotificationIdentifier.get().getPeopleNotificationType(entry);
-        return peopleNotificationType == PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON;
-    }
-
-    /**
-     * Isolate a notification from its group so that it visually shows as its own group.
-     *
-     * @param entry the notification to isolate
-     */
-    private void isolateNotification(NotificationEntry entry) {
-        if (SPEW) {
-            Log.d(TAG, "isolateNotification: entry=" + logKey(entry));
-        }
-        // We will be isolated now, so lets update the groups
-        onEntryRemovedInternal(entry, entry.getSbn());
-
-        mIsolatedEntries.put(entry.getKey(), entry.getSbn());
-
-        onEntryAddedInternal(entry);
-        // We also need to update the suppression of the old group, because this call comes
-        // even before the groupManager knows about the notification at all.
-        // When the notification gets added afterwards it is already isolated and therefore
-        // it doesn't lead to an update.
-        updateSuppression(mGroupMap.get(entry.getSbn().getGroupKey()));
-        mEventDispatcher.notifyGroupsChanged();
-    }
-
-    /**
-     * Update the isolation of an entry, splitting it from the group.
-     */
-    private void updateIsolation(NotificationEntry entry) {
-        // We need to buffer a few events because we do isolation changes in 3 steps:
-        // removeInternal, update mIsolatedEntries, addInternal.  This means that often the
-        // alertOverride will update on the removal, however processing the event in that case can
-        // cause problems because the mIsolatedEntries map is not in its final state, so the event
-        // listener may be unable to correctly determine the true state of the group.  By delaying
-        // the alertOverride change until after the add phase, we can ensure that listeners only
-        // have to handle a consistent state.
-        mEventDispatcher.openBufferScope();
-        boolean isIsolated = isIsolated(entry.getSbn().getKey());
-        if (shouldIsolate(entry)) {
-            if (!isIsolated) {
-                isolateNotification(entry);
-            }
-        } else if (isIsolated) {
-            stopIsolatingNotification(entry);
-        }
-        mEventDispatcher.closeBufferScope();
-    }
-
-    /**
-     * Stop isolating a notification and re-group it with its original logical group.
-     *
-     * @param entry the notification to un-isolate
-     */
-    private void stopIsolatingNotification(NotificationEntry entry) {
-        if (SPEW) {
-            Log.d(TAG, "stopIsolatingNotification: entry=" + logKey(entry));
-        }
-        // not isolated anymore, we need to update the groups
-        onEntryRemovedInternal(entry, entry.getSbn());
-        mIsolatedEntries.remove(entry.getKey());
-        onEntryAddedInternal(entry);
-        mEventDispatcher.notifyGroupsChanged();
-    }
-
-    private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) {
-        return notificationGroup.summary == null
-                || notificationGroup.summary.isGroupNotFullyVisible();
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String[] args) {
-        pw.println("GroupManagerLegacy state:");
-        pw.println("  number of groups: " +  mGroupMap.size());
-        for (Map.Entry<String, NotificationGroup>  entry : mGroupMap.entrySet()) {
-            pw.println("\n    key: " + logKey(entry.getKey())); pw.println(entry.getValue());
-        }
-        pw.println("\n    isolated entries: " +  mIsolatedEntries.size());
-        for (Map.Entry<String, StatusBarNotification> entry : mIsolatedEntries.entrySet()) {
-            pw.print("      "); pw.print(logKey(entry.getKey()));
-            pw.print(", "); pw.println(entry.getValue());
-        }
-    }
-
-    @Override
-    public void onStateChanged(int newState) {
-        setStatusBarState(newState);
-    }
-
-    /** Get the group key, reformatted for logging, for the (optional) group */
-    private static String logGroupKey(NotificationGroup group) {
-        if (group == null) {
-            return "null";
-        }
-        return logKey(group.groupKey);
-    }
-
-    /**
-     * A record of a notification being posted, containing the time of the post and the key of the
-     * notification entry.  These are stored in a TreeSet by the NotificationGroup and used to
-     * calculate a batch of notifications.
-     */
-    public static class PostRecord implements Comparable<PostRecord> {
-        public final long postTime;
-        public final String key;
-
-        /** constructs a record containing the post time and key from the notification entry */
-        public PostRecord(@NonNull NotificationEntry entry) {
-            this.postTime = entry.getSbn().getPostTime();
-            this.key = entry.getKey();
-        }
-
-        @Override
-        public int compareTo(PostRecord o) {
-            int postTimeComparison = Long.compare(this.postTime, o.postTime);
-            return postTimeComparison == 0
-                    ? String.CASE_INSENSITIVE_ORDER.compare(this.key, o.key)
-                    : postTimeComparison;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-            PostRecord that = (PostRecord) o;
-            return postTime == that.postTime && key.equals(that.key);
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(postTime, key);
-        }
-    }
-
-    /**
-     * Represents a notification group in the notification shade.
-     */
-    public static class NotificationGroup {
-        public final String groupKey;
-        public final HashMap<String, NotificationEntry> children = new HashMap<>();
-        public final TreeSet<PostRecord> postBatchHistory = new TreeSet<>();
-        public NotificationEntry summary;
-        public boolean expanded;
-        /**
-         * Is this notification group suppressed, i.e its summary is hidden
-         */
-        public boolean suppressed;
-        /**
-         * The child (which is isolated from this group) to which the alert should be transferred,
-         * due to priority conversations.
-         */
-        public NotificationEntry alertOverride;
-
-        NotificationGroup(String groupKey) {
-            this.groupKey = groupKey;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("    groupKey: ").append(groupKey);
-            sb.append("\n    summary:");
-            appendEntry(sb, summary);
-            sb.append("\n    children size: ").append(children.size());
-            for (NotificationEntry child : children.values()) {
-                appendEntry(sb, child);
-            }
-            sb.append("\n    alertOverride:");
-            appendEntry(sb, alertOverride);
-            sb.append("\n    summary suppressed: ").append(suppressed);
-            return sb.toString();
-        }
-
-        private void appendEntry(StringBuilder sb, NotificationEntry entry) {
-            sb.append("\n      ").append(entry != null ? entry.getSbn() : "null");
-            if (entry != null && entry.getDebugThrowable() != null) {
-                sb.append(Log.getStackTraceString(entry.getDebugThrowable()));
-            }
-        }
-    }
-
-    /**
-     * This class is a toggleable buffer for a subset of events of {@link OnGroupChangeListener}.
-     * When buffering, instead of notifying the listeners it will set internal state that will allow
-     * it to notify listeners of those events later
-     */
-    static class GroupEventDispatcher {
-        private final Function<String, NotificationGroup> mGroupMapGetter;
-        private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
-        private final HashMap<String, NotificationEntry> mOldAlertOverrideByGroup = new HashMap<>();
-        private final HashMap<String, Boolean> mOldSuppressedByGroup = new HashMap<>();
-        private int mBufferScopeDepth = 0;
-        private boolean mDidGroupsChange = false;
-
-        GroupEventDispatcher(Function<String, NotificationGroup> groupMapGetter) {
-            mGroupMapGetter = requireNonNull(groupMapGetter);
-        }
-
-        void registerGroupChangeListener(OnGroupChangeListener listener) {
-            mGroupChangeListeners.add(listener);
-        }
-
-        private boolean isBuffering() {
-            return mBufferScopeDepth > 0;
-        }
-
-        void notifyAlertOverrideChanged(NotificationGroup group,
-                NotificationEntry oldAlertOverride) {
-            if (isBuffering()) {
-                // The value in this map is the override before the event.  If there is an entry
-                // already in the map, then we are effectively coalescing two events, which means
-                // we need to preserve the original initial value.
-                if (!mOldAlertOverrideByGroup.containsKey(group.groupKey)) {
-                    mOldAlertOverrideByGroup.put(group.groupKey, oldAlertOverride);
-                }
-            } else {
-                for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                    listener.onGroupAlertOverrideChanged(group, oldAlertOverride,
-                            group.alertOverride);
-                }
-            }
-        }
-
-        void notifySuppressedChanged(NotificationGroup group) {
-            if (isBuffering()) {
-                // The value in this map is the 'suppressed' before the event.  If there is a value
-                // already in the map, then we are effectively coalescing two events, which means
-                // we need to preserve the original initial value.
-                mOldSuppressedByGroup.putIfAbsent(group.groupKey, !group.suppressed);
-            } else {
-                for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                    listener.onGroupSuppressionChanged(group, group.suppressed);
-                }
-            }
-        }
-
-        void notifyGroupsChanged() {
-            if (isBuffering()) {
-                mDidGroupsChange = true;
-            } else {
-                for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                    listener.onGroupsChanged();
-                }
-            }
-        }
-
-        void notifyGroupCreated(NotificationGroup group) {
-            // NOTE: given how this event is used, it doesn't need to be buffered right now
-            final String groupKey = group.groupKey;
-            for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                listener.onGroupCreated(group, groupKey);
-            }
-        }
-
-        void notifyGroupRemoved(NotificationGroup group) {
-            // NOTE: given how this event is used, it doesn't need to be buffered right now
-            final String groupKey = group.groupKey;
-            for (OnGroupChangeListener listener : mGroupChangeListeners) {
-                listener.onGroupRemoved(group, groupKey);
-            }
-        }
-
-        void openBufferScope() {
-            mBufferScopeDepth++;
-            if (SPEW) {
-                Log.d(TAG, "openBufferScope: scopeDepth=" + mBufferScopeDepth);
-            }
-        }
-
-        void closeBufferScope() {
-            mBufferScopeDepth--;
-            if (SPEW) {
-                Log.d(TAG, "closeBufferScope: scopeDepth=" + mBufferScopeDepth);
-            }
-            // Flush buffered events if the last buffer scope has closed
-            if (!isBuffering()) {
-                flushBuffer();
-            }
-        }
-
-        private void flushBuffer() {
-            if (SPEW) {
-                Log.d(TAG, "flushBuffer: "
-                        + " suppressed.size=" + mOldSuppressedByGroup.size()
-                        + " alertOverride.size=" + mOldAlertOverrideByGroup.size()
-                        + " mDidGroupsChange=" + mDidGroupsChange);
-            }
-            // alert all group suppressed changes for groups that were not removed
-            for (Map.Entry<String, Boolean> entry : mOldSuppressedByGroup.entrySet()) {
-                NotificationGroup group = mGroupMapGetter.apply(entry.getKey());
-                if (group == null) {
-                    // The group can be null if this suppressed changed before the group was
-                    // permanently removed, meaning that there's no guarantee that listeners will
-                    // that field clear.
-                    if (SPEW) {
-                        Log.d(TAG, "flushBuffer: suppressed:"
-                                + " cannot report for removed group: " + logKey(entry.getKey()));
-                    }
-                    continue;
-                }
-                boolean oldSuppressed = entry.getValue();
-                if (group.suppressed == oldSuppressed) {
-                    // If the final suppressed equals the initial, it means we coalesced two
-                    // events which undid the change, so we can drop it entirely.
-                    if (SPEW) {
-                        Log.d(TAG, "flushBuffer: suppressed:"
-                                + " did not change for group: " + logKey(entry.getKey()));
-                    }
-                    continue;
-                }
-                notifySuppressedChanged(group);
-            }
-            mOldSuppressedByGroup.clear();
-            // alert all group alert override changes for groups that were not removed
-            for (Map.Entry<String, NotificationEntry> entry : mOldAlertOverrideByGroup.entrySet()) {
-                NotificationGroup group = mGroupMapGetter.apply(entry.getKey());
-                if (group == null) {
-                    // The group can be null if this alertOverride changed before the group was
-                    // permanently removed, meaning that there's no guarantee that listeners will
-                    // that field clear.
-                    if (SPEW) {
-                        Log.d(TAG, "flushBuffer: alertOverride:"
-                                + " cannot report for removed group: " + entry.getKey());
-                    }
-                    continue;
-                }
-                NotificationEntry oldAlertOverride = entry.getValue();
-                if (group.alertOverride == oldAlertOverride) {
-                    // If the final alertOverride equals the initial, it means we coalesced two
-                    // events which undid the change, so we can drop it entirely.
-                    if (SPEW) {
-                        Log.d(TAG, "flushBuffer: alertOverride:"
-                                + " did not change for group: " + logKey(entry.getKey()));
-                    }
-                    continue;
-                }
-                notifyAlertOverrideChanged(group, oldAlertOverride);
-            }
-            mOldAlertOverrideByGroup.clear();
-            // alert that groups changed
-            if (mDidGroupsChange) {
-                notifyGroupsChanged();
-                mDidGroupsChange = false;
-            }
-        }
-    }
-
-    /**
-     * Listener for group changes not including group expansion changes which are handled by
-     * {@link OnGroupExpansionChangeListener}.
-     */
-    public interface OnGroupChangeListener {
-        /**
-         * A new group has been created.
-         *
-         * @param group the group that was created
-         * @param groupKey the group's key
-         */
-        default void onGroupCreated(
-                NotificationGroup group,
-                String groupKey) {}
-
-        /**
-         * A group has been removed.
-         *
-         * @param group the group that was removed
-         * @param groupKey the group's key
-         */
-        default void onGroupRemoved(
-                NotificationGroup group,
-                String groupKey) {}
-
-        /**
-         * The suppression of a group has changed.
-         *
-         * @param group the group that has changed
-         * @param suppressed true if the group is now suppressed, false o/w
-         */
-        default void onGroupSuppressionChanged(
-                NotificationGroup group,
-                boolean suppressed) {}
-
-        /**
-         * The alert override of a group has changed.
-         *
-         * @param group the group that has changed
-         * @param oldAlertOverride the previous notification to which the group's alerts were sent
-         * @param newAlertOverride the notification to which the group's alerts should now be sent
-         */
-        default void onGroupAlertOverrideChanged(
-                NotificationGroup group,
-                @Nullable NotificationEntry oldAlertOverride,
-                @Nullable NotificationEntry newAlertOverride) {}
-
-        /**
-         * The groups have changed. This can happen if the isolation of a child has changes or if a
-         * group became suppressed / unsuppressed
-         */
-        default void onGroupsChanged() {}
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java
deleted file mode 100644
index bb8c0e0..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/VisualStabilityManager.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection.legacy;
-
-import com.android.systemui.keyguard.WakefulnessLifecycle;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
-import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-
-/**
- * A manager that ensures that notifications are visually stable. It will suppress reorderings
- * and reorder at the right time when they are out of view.
- */
-public class VisualStabilityManager {
-
-    private final VisualStabilityProvider mVisualStabilityProvider;
-
-    private boolean mPanelExpanded;
-    private boolean mScreenOn;
-    private boolean mPulsing;
-
-    /**
-     * Injected constructor. See {@link NotificationsModule}.
-     */
-    public VisualStabilityManager(
-            VisualStabilityProvider visualStabilityProvider,
-            StatusBarStateController statusBarStateController,
-            WakefulnessLifecycle wakefulnessLifecycle) {
-
-        mVisualStabilityProvider = visualStabilityProvider;
-
-        if (statusBarStateController != null) {
-            setPulsing(statusBarStateController.isPulsing());
-            statusBarStateController.addCallback(new StatusBarStateController.StateListener() {
-                @Override
-                public void onPulsingChanged(boolean pulsing) {
-                    setPulsing(pulsing);
-                }
-
-                @Override
-                public void onExpandedChanged(boolean expanded) {
-                    setPanelExpanded(expanded);
-                }
-            });
-        }
-
-        if (wakefulnessLifecycle != null) {
-            wakefulnessLifecycle.addObserver(mWakefulnessObserver);
-        }
-    }
-
-    /**
-     * @param screenOn whether the screen is on
-     */
-    private void setScreenOn(boolean screenOn) {
-        mScreenOn = screenOn;
-        updateAllowedStates();
-    }
-
-    /**
-     * Set the panel to be expanded.
-     */
-    private void setPanelExpanded(boolean expanded) {
-        mPanelExpanded = expanded;
-        updateAllowedStates();
-    }
-
-    /**
-     * @param pulsing whether we are currently pulsing for ambient display.
-     */
-    private void setPulsing(boolean pulsing) {
-        if (mPulsing == pulsing) {
-            return;
-        }
-        mPulsing = pulsing;
-        updateAllowedStates();
-    }
-
-    private void updateAllowedStates() {
-        boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
-        mVisualStabilityProvider.setReorderingAllowed(reorderingAllowed);
-    }
-
-    final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() {
-        @Override
-        public void onFinishedGoingToSleep() {
-            setScreenOn(false);
-        }
-
-        @Override
-        public void onStartedWakingUp() {
-            setScreenOn(true);
-        }
-    };
-
-
-    /**
-     * See {@link Callback#onChangeAllowed()}
-     */
-    public interface Callback {
-
-        /**
-         * Called when changing is allowed again.
-         */
-        void onChangeAllowed();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
index 4ff6a64..fc7d682 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/CommonNotifCollection.java
@@ -19,7 +19,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
@@ -29,9 +28,8 @@
  * A notification collection that manages the list of {@link NotificationEntry}s that will be
  * rendered.
  *
- * TODO: (b/145659174) Once we fully switch off {@link NotificationEntryManager} to
- * {@link NotifPipeline}, we probably won't need this, but having it for now makes it easy to
- * switch between the two.
+ * TODO: (b/145659174) Once we fully migrate to {@link NotifPipeline}, we probably won't need this,
+ * but having it for now makes it easy to switch between the two.
  */
 public interface CommonNotifCollection {
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index eda2eec..da4cced 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -24,24 +24,18 @@
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.internal.logging.UiEventLogger;
-import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
-import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.settings.UserContextProvider;
 import com.android.systemui.shade.NotifPanelEventsModule;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
@@ -53,12 +47,9 @@
 import com.android.systemui.statusbar.notification.collection.inflation.BindEventManagerImpl;
 import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
 import com.android.systemui.statusbar.notification.collection.inflation.OnUserInteractionCallbackImpl;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl;
-import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -84,7 +75,6 @@
 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.util.leak.LeakDetector;
 import com.android.systemui.wmshell.BubblesManager;
 
 import java.util.Optional;
@@ -114,22 +104,6 @@
     @Binds
     StackScrollAlgorithm.BypassController bindBypassController(KeyguardBypassController impl);
 
-    /** Provides an instance of {@link NotificationEntryManager} */
-    @SysUISingleton
-    @Provides
-    static NotificationEntryManager provideNotificationEntryManager(
-            NotificationEntryManagerLogger logger,
-            NotificationGroupManagerLegacy groupManager,
-            NotifPipelineFlags notifPipelineFlags,
-            Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
-            LeakDetector leakDetector,
-            IStatusBarService statusBarService,
-            @Background Executor bgExecutor) {
-        return new NotificationEntryManager(
-                logger
-        );
-    }
-
     /** Provides an instance of {@link NotificationGutsManager} */
     @SysUISingleton
     @Provides
@@ -141,7 +115,6 @@
             AccessibilityManager accessibilityManager,
             HighPriorityProvider highPriorityProvider,
             INotificationManager notificationManager,
-            NotificationEntryManager notificationEntryManager,
             PeopleSpaceWidgetManager peopleSpaceWidgetManager,
             LauncherApps launcherApps,
             ShortcutManager shortcutManager,
@@ -177,20 +150,6 @@
     @Binds
     NotifGutsViewManager bindNotifGutsViewManager(NotificationGutsManager notificationGutsManager);
 
-    /** Provides an instance of {@link VisualStabilityManager} */
-    @SysUISingleton
-    @Provides
-    static VisualStabilityManager provideVisualStabilityManager(
-            VisualStabilityProvider visualStabilityProvider,
-            StatusBarStateController statusBarStateController,
-            WakefulnessLifecycle wakefulnessLifecycle) {
-        return new VisualStabilityManager(
-                visualStabilityProvider,
-                statusBarStateController,
-                wakefulnessLifecycle
-        );
-    }
-
     /** Provides an instance of {@link NotificationLogger} */
     @SysUISingleton
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
index 3b10b20..a5278c3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import java.io.PrintWriter
 
 /**
  * The master controller for all notifications-related work
@@ -42,9 +41,7 @@
         bindRowCallback: NotificationRowBinderImpl.BindRowCallback
     )
 
-    fun requestNotificationUpdate(reason: String)
     fun resetUserExpandedStates()
     fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption)
     fun getActiveNotificationsCount(): Int
-    fun dump(pw: PrintWriter, args: Array<String>, dumpTruck: Boolean)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
index 385fbb5..801e544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.init
 
 import android.service.notification.StatusBarNotification
+import com.android.systemui.ForegroundServiceNotificationListener
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
@@ -26,24 +27,22 @@
 import com.android.systemui.statusbar.notification.AnimatedImageNotificationManager
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.NotificationClicker
-import com.android.systemui.statusbar.notification.NotificationEntryManager
-import com.android.systemui.statusbar.notification.NotificationListController
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.TargetSdkResolver
 import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
 import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController
 import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder
 import com.android.systemui.statusbar.notification.logging.NotificationLogger
 import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.wm.shell.bubbles.Bubbles
 import dagger.Lazy
-import java.io.PrintWriter
 import java.util.Optional
 import javax.inject.Inject
 
@@ -57,7 +56,6 @@
 @SysUISingleton
 class NotificationsControllerImpl @Inject constructor(
     private val notificationListener: NotificationListener,
-    private val entryManager: NotificationEntryManager,
     private val commonNotifCollection: Lazy<CommonNotifCollection>,
     private val notifPipeline: Lazy<NotifPipeline>,
     private val notifLiveDataStore: NotifLiveDataStore,
@@ -65,7 +63,6 @@
     private val notifPipelineInitializer: Lazy<NotifPipelineInitializer>,
     private val notifBindPipelineInitializer: NotifBindPipelineInitializer,
     private val notificationLogger: NotificationLogger,
-    private val deviceProvisionedController: DeviceProvisionedController,
     private val notificationRowBinder: NotificationRowBinderImpl,
     private val notificationsMediaManager: NotificationMediaManager,
     private val headsUpViewBinder: HeadsUpViewBinder,
@@ -73,6 +70,7 @@
     private val animatedImageNotificationManager: AnimatedImageNotificationManager,
     private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
     private val bubblesOptional: Optional<Bubbles>,
+    private val fgsNotifListener: ForegroundServiceNotificationListener,
 ) : NotificationsController {
 
     override fun initialize(
@@ -85,12 +83,11 @@
     ) {
         notificationListener.registerAsSystemService()
 
-        val listController =
-                NotificationListController(
-                        entryManager,
-                        listContainer,
-                        deviceProvisionedController)
-        listController.bind()
+        notifPipeline.get().addCollectionListener(object : NotifCollectionListener {
+            override fun onEntryRemoved(entry: NotificationEntry, reason: Int) {
+                listContainer.cleanUpViewStateForEntry(entry)
+            }
+        })
 
         notificationRowBinder.setNotificationClicker(
                 clickerBuilder.build(
@@ -114,24 +111,11 @@
         notificationsMediaManager.setUpWithPresenter(presenter)
         notificationLogger.setUpWithContainer(listContainer)
         peopleSpaceWidgetManager.attach(notificationListener)
-    }
-
-    override fun dump(
-        pw: PrintWriter,
-        args: Array<String>,
-        dumpTruck: Boolean
-    ) {
-        if (dumpTruck) {
-            entryManager.dump(pw, "  ")
-        }
+        fgsNotifListener.init()
     }
 
     // TODO: Convert all functions below this line into listeners instead of public methods
 
-    override fun requestNotificationUpdate(reason: String) {
-        entryManager.updateNotifications(reason)
-    }
-
     override fun resetUserExpandedStates() {
         // TODO: this is a view thing that should be done through the views, but that means doing it
         //  both when this event is fired and any time a row is attached.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
index 06a9eac..14856da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -25,7 +25,6 @@
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.CentralSurfaces
-import java.io.PrintWriter
 import javax.inject.Inject
 
 /**
@@ -48,9 +47,6 @@
         notificationListener.registerAsSystemService()
     }
 
-    override fun requestNotificationUpdate(reason: String) {
-    }
-
     override fun resetUserExpandedStates() {
     }
 
@@ -60,14 +56,4 @@
     override fun getActiveNotificationsCount(): Int {
         return 0
     }
-
-    override fun dump(
-        pw: PrintWriter,
-        args: Array<String>,
-        dumpTruck: Boolean
-    ) {
-        pw.println()
-        pw.println("Notification handling disabled")
-        pw.println()
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt
new file mode 100644
index 0000000..4cf3572
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractor.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.people
+
+import android.service.notification.StatusBarNotification
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.plugins.NotificationPersonExtractorPlugin
+import com.android.systemui.statusbar.policy.ExtensionController
+import javax.inject.Inject
+
+interface NotificationPersonExtractor {
+    fun isPersonNotification(sbn: StatusBarNotification): Boolean
+}
+
+@SysUISingleton
+class NotificationPersonExtractorPluginBoundary @Inject constructor(
+    extensionController: ExtensionController
+) : NotificationPersonExtractor {
+
+    private var plugin: NotificationPersonExtractorPlugin? = null
+
+    init {
+        plugin = extensionController
+                .newExtension(NotificationPersonExtractorPlugin::class.java)
+                .withPlugin(NotificationPersonExtractorPlugin::class.java)
+                .withCallback { extractor ->
+                    plugin = extractor
+                }
+                .build()
+                .get()
+    }
+
+    override fun isPersonNotification(sbn: StatusBarNotification): Boolean =
+            plugin?.isPersonNotification(sbn) ?: false
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
deleted file mode 100644
index 3af6ba8..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHub.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.people
-
-import android.graphics.drawable.Drawable
-
-/**
- * `ViewModel` for PeopleHub view.
- *
- * @param people ViewModels for individual people in PeopleHub, in order that they should be
- *  displayed
- * @param isVisible Whether or not the whole PeopleHub UI is visible
- **/
-data class PeopleHubViewModel(val people: Sequence<PersonViewModel>, val isVisible: Boolean)
-
-/** `ViewModel` for a single "Person' in PeopleHub. */
-data class PersonViewModel(
-    val name: CharSequence,
-    val icon: Drawable,
-    val onClick: () -> Unit
-)
-
-/**
- * `Model` for PeopleHub.
- *
- * @param people Models for individual people in PeopleHub, in order that they should be displayed
- **/
-data class PeopleHubModel(val people: Collection<PersonModel>)
-
-/** `Model` for a single "Person" in PeopleHub. */
-data class PersonModel(
-    val key: PersonKey,
-    val userId: Int,
-    // TODO: these should live in the ViewModel
-    val name: CharSequence,
-    val avatar: Drawable,
-    val clickRunnable: Runnable
-)
-
-/** Unique identifier for a Person in PeopleHub. */
-typealias PersonKey = String
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
index 16574ab..c17ffb0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt
@@ -21,25 +21,6 @@
 
 @Module
 abstract class PeopleHubModule {
-
-    @Binds
-    abstract fun peopleHubSectionFooterViewAdapter(
-        impl: PeopleHubViewAdapterImpl
-    ): PeopleHubViewAdapter
-
-    @Binds
-    abstract fun peopleHubDataSource(impl: PeopleHubDataSourceImpl): DataSource<PeopleHubModel>
-
-    @Binds
-    abstract fun peopleHubSettingChangeDataSource(
-        impl: PeopleHubSettingChangeDataSourceImpl
-    ): DataSource<Boolean>
-
-    @Binds
-    abstract fun peopleHubViewModelFactoryDataSource(
-        impl: PeopleHubViewModelFactoryDataSourceImpl
-    ): DataSource<PeopleHubViewModelFactory>
-
     @Binds
     abstract fun peopleNotificationIdentifier(
         impl: PeopleNotificationIdentifierImpl
@@ -49,4 +30,4 @@
     abstract fun notificationPersonExtractor(
         pluginImpl: NotificationPersonExtractorPluginBoundary
     ): NotificationPersonExtractor
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
deleted file mode 100644
index 6062941..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubNotificationListener.kt
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.people
-
-import android.app.Notification
-import android.content.Context
-import android.content.pm.LauncherApps
-import android.content.pm.PackageManager
-import android.content.pm.UserInfo
-import android.graphics.drawable.Drawable
-import android.os.UserManager
-import android.service.notification.NotificationListenerService
-import android.service.notification.NotificationListenerService.REASON_SNOOZED
-import android.service.notification.StatusBarNotification
-import android.util.IconDrawableFactory
-import android.util.SparseArray
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import com.android.internal.widget.MessagingGroup
-import com.android.settingslib.notification.ConversationIconFactory
-import com.android.systemui.R
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.NotificationPersonExtractorPlugin
-import com.android.systemui.statusbar.NotificationListener
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
-import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
-import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_NON_PERSON
-import com.android.systemui.statusbar.policy.ExtensionController
-import java.util.ArrayDeque
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-private const val MAX_STORED_INACTIVE_PEOPLE = 10
-
-interface NotificationPersonExtractor {
-    fun extractPerson(sbn: StatusBarNotification): PersonModel?
-    fun extractPersonKey(sbn: StatusBarNotification): String?
-    fun isPersonNotification(sbn: StatusBarNotification): Boolean
-}
-
-@SysUISingleton
-class NotificationPersonExtractorPluginBoundary @Inject constructor(
-    extensionController: ExtensionController
-) : NotificationPersonExtractor {
-
-    private var plugin: NotificationPersonExtractorPlugin? = null
-
-    init {
-        plugin = extensionController
-                .newExtension(NotificationPersonExtractorPlugin::class.java)
-                .withPlugin(NotificationPersonExtractorPlugin::class.java)
-                .withCallback { extractor ->
-                    plugin = extractor
-                }
-                .build()
-                .get()
-    }
-
-    override fun extractPerson(sbn: StatusBarNotification) =
-            plugin?.extractPerson(sbn)?.run {
-                PersonModel(key, sbn.user.identifier, name, avatar, clickRunnable)
-            }
-
-    override fun extractPersonKey(sbn: StatusBarNotification) = plugin?.extractPersonKey(sbn)
-
-    override fun isPersonNotification(sbn: StatusBarNotification): Boolean =
-            plugin?.isPersonNotification(sbn) ?: false
-}
-
-@SysUISingleton
-class PeopleHubDataSourceImpl @Inject constructor(
-    private val notifCollection: CommonNotifCollection,
-    private val extractor: NotificationPersonExtractor,
-    private val userManager: UserManager,
-    launcherApps: LauncherApps,
-    packageManager: PackageManager,
-    context: Context,
-    private val notificationListener: NotificationListener,
-    @Background private val bgExecutor: Executor,
-    @Main private val mainExecutor: Executor,
-    private val notifLockscreenUserMgr: NotificationLockscreenUserManager,
-    private val peopleNotificationIdentifier: PeopleNotificationIdentifier
-) : DataSource<PeopleHubModel> {
-
-    private var userChangeSubscription: Subscription? = null
-    private val dataListeners = mutableListOf<DataListener<PeopleHubModel>>()
-    private val peopleHubManagerForUser = SparseArray<PeopleHubManager>()
-
-    private val iconFactory = run {
-        val appContext = context.applicationContext
-        ConversationIconFactory(
-                appContext,
-                launcherApps,
-                packageManager,
-                IconDrawableFactory.newInstance(appContext),
-                appContext.resources.getDimensionPixelSize(
-                        R.dimen.notification_guts_conversation_icon_size
-                )
-        )
-    }
-
-    private val notifCollectionListener = object : NotifCollectionListener {
-        override fun onEntryAdded(entry: NotificationEntry) = addVisibleEntry(entry)
-        override fun onEntryUpdated(entry: NotificationEntry) = addVisibleEntry(entry)
-        override fun onEntryRemoved(entry: NotificationEntry, reason: Int) =
-            removeVisibleEntry(entry, reason)
-    }
-
-    private fun removeVisibleEntry(entry: NotificationEntry, reason: Int) {
-        (extractor.extractPersonKey(entry.sbn) ?: entry.extractPersonKey())?.let { key ->
-            val userId = entry.sbn.user.identifier
-            bgExecutor.execute {
-                val parentId = userManager.getProfileParent(userId)?.id ?: userId
-                mainExecutor.execute {
-                    if (reason == REASON_SNOOZED) {
-                        if (peopleHubManagerForUser[parentId]?.migrateActivePerson(key) == true) {
-                            updateUi()
-                        }
-                    } else {
-                        peopleHubManagerForUser[parentId]?.removeActivePerson(key)
-                    }
-                }
-            }
-        }
-    }
-
-    private fun addVisibleEntry(entry: NotificationEntry) {
-        entry.extractPerson()?.let { personModel ->
-            val userId = entry.sbn.user.identifier
-            bgExecutor.execute {
-                val parentId = userManager.getProfileParent(userId)?.id ?: userId
-                mainExecutor.execute {
-                    val manager = peopleHubManagerForUser[parentId]
-                            ?: PeopleHubManager().also { peopleHubManagerForUser.put(parentId, it) }
-                    if (manager.addActivePerson(personModel)) {
-                        updateUi()
-                    }
-                }
-            }
-        }
-    }
-
-    override fun registerListener(listener: DataListener<PeopleHubModel>): Subscription {
-        val register = dataListeners.isEmpty()
-        dataListeners.add(listener)
-        if (register) {
-            userChangeSubscription = notifLockscreenUserMgr.registerListener(
-                    object : NotificationLockscreenUserManager.UserChangedListener {
-                        override fun onUserChanged(userId: Int) = updateUi()
-                        override fun onCurrentProfilesChanged(
-                            currentProfiles: SparseArray<UserInfo>?
-                        ) = updateUi()
-                    })
-            notifCollection.addCollectionListener(notifCollectionListener)
-        } else {
-            getPeopleHubModelForCurrentUser()?.let(listener::onDataChanged)
-        }
-        return object : Subscription {
-            override fun unsubscribe() {
-                dataListeners.remove(listener)
-                if (dataListeners.isEmpty()) {
-                    userChangeSubscription?.unsubscribe()
-                    userChangeSubscription = null
-                    notifCollection.removeCollectionListener(notifCollectionListener)
-                }
-            }
-        }
-    }
-
-    private fun getPeopleHubModelForCurrentUser(): PeopleHubModel? {
-        val currentUserId = notifLockscreenUserMgr.currentUserId
-        val model = peopleHubManagerForUser[currentUserId]?.getPeopleHubModel()
-                ?: return null
-        val currentProfiles = notifLockscreenUserMgr.currentProfiles
-        return model.copy(people = model.people.filter { person ->
-            currentProfiles[person.userId]?.isQuietModeEnabled == false
-        })
-    }
-
-    private fun updateUi() {
-        val model = getPeopleHubModelForCurrentUser() ?: return
-        for (listener in dataListeners) {
-            listener.onDataChanged(model)
-        }
-    }
-
-    private fun NotificationEntry.extractPerson(): PersonModel? {
-        val type = peopleNotificationIdentifier.getPeopleNotificationType(this)
-        if (type == TYPE_NON_PERSON) {
-            return null
-        }
-        val clickRunnable = Runnable { notificationListener.unsnoozeNotification(key) }
-        val extras = sbn.notification.extras
-        val name = ranking.conversationShortcutInfo?.label
-                ?: extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE)
-                ?: extras.getCharSequence(Notification.EXTRA_TITLE)
-                ?: return null
-        val drawable = ranking.getIcon(iconFactory, sbn)
-                ?: iconFactory.getConversationDrawable(
-                        extractAvatarFromRow(this),
-                        sbn.packageName,
-                        sbn.uid,
-                        ranking.channel.isImportantConversation
-                )
-        return PersonModel(key, sbn.user.identifier, name, drawable, clickRunnable)
-    }
-
-    private fun NotificationListenerService.Ranking.getIcon(
-        iconFactory: ConversationIconFactory,
-        sbn: StatusBarNotification
-    ): Drawable? =
-            conversationShortcutInfo?.let { conversationShortcutInfo ->
-                iconFactory.getConversationDrawable(
-                        conversationShortcutInfo,
-                        sbn.packageName,
-                        sbn.uid,
-                        channel.isImportantConversation
-                )
-            }
-
-    private fun NotificationEntry.extractPersonKey(): PersonKey? {
-        // TODO migrate to shortcut id when snoozing is conversation wide
-        val type = peopleNotificationIdentifier.getPeopleNotificationType(this)
-        return if (type != TYPE_NON_PERSON) key else null
-    }
-}
-
-private fun NotificationLockscreenUserManager.registerListener(
-    listener: NotificationLockscreenUserManager.UserChangedListener
-): Subscription {
-    addUserChangedListener(listener)
-    return object : Subscription {
-        override fun unsubscribe() {
-            removeUserChangedListener(listener)
-        }
-    }
-}
-
-class PeopleHubManager {
-
-    // People currently visible in the notification shade, and so are not in the hub
-    private val activePeople = mutableMapOf<PersonKey, PersonModel>()
-
-    // People that were once "active" and have been dismissed, and so can be displayed in the hub
-    private val inactivePeople = ArrayDeque<PersonModel>(MAX_STORED_INACTIVE_PEOPLE)
-
-    fun migrateActivePerson(key: PersonKey): Boolean {
-        activePeople.remove(key)?.let { data ->
-            if (inactivePeople.size >= MAX_STORED_INACTIVE_PEOPLE) {
-                inactivePeople.removeLast()
-            }
-            inactivePeople.addFirst(data)
-            return true
-        }
-        return false
-    }
-
-    fun removeActivePerson(key: PersonKey) {
-        activePeople.remove(key)
-    }
-
-    fun addActivePerson(person: PersonModel): Boolean {
-        activePeople[person.key] = person
-        return inactivePeople.removeIf { it.key == person.key }
-    }
-
-    fun getPeopleHubModel(): PeopleHubModel = PeopleHubModel(inactivePeople)
-}
-
-private val ViewGroup.children
-    get(): Sequence<View> = sequence {
-        for (i in 0 until childCount) {
-            yield(getChildAt(i))
-        }
-    }
-
-private fun ViewGroup.childrenWithId(id: Int): Sequence<View> = children.filter { it.id == id }
-
-fun extractAvatarFromRow(entry: NotificationEntry): Drawable? =
-        entry.row
-                ?.childrenWithId(R.id.expanded)
-                ?.mapNotNull { it as? ViewGroup }
-                ?.flatMap {
-                    it.childrenWithId(com.android.internal.R.id.status_bar_latest_event_content)
-                }
-                ?.mapNotNull {
-                    it.findViewById<ViewGroup>(com.android.internal.R.id.notification_messaging)
-                }
-                ?.mapNotNull { messagesView ->
-                    messagesView.children
-                            .mapNotNull { it as? MessagingGroup }
-                            .lastOrNull()
-                            ?.findViewById<ImageView>(com.android.internal.R.id.message_icon)
-                            ?.drawable
-                }
-                ?.firstOrNull()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
deleted file mode 100644
index 55bd77f..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.people
-
-import android.content.Context
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.os.UserHandle
-import android.provider.Settings
-import android.view.View
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.ActivityStarter
-import javax.inject.Inject
-
-/** Boundary between the View and PeopleHub, as seen by the View. */
-interface PeopleHubViewAdapter {
-    fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription
-}
-
-/** Abstract `View` representation of PeopleHub. */
-interface PeopleHubViewBoundary {
-    /** View used for animating the activity launch caused by clicking a person in the hub. */
-    val associatedViewForClickAnimation: View
-
-    /**
-     * [DataListener]s for individual people in the hub.
-     *
-     * These listeners should be ordered such that the first element will be bound to the most
-     * recent person to be added to the hub, and then continuing in descending order. If there are
-     * not enough people to satisfy each listener, `null` will be passed instead, indicating that
-     * the `View` should render a placeholder.
-     */
-    val personViewAdapters: Sequence<DataListener<PersonViewModel?>>
-
-    /** Sets the visibility of the Hub in the notification shade. */
-    fun setVisible(isVisible: Boolean)
-}
-
-/** Creates a [PeopleHubViewModel] given some additional information required from the `View`. */
-interface PeopleHubViewModelFactory {
-
-    /**
-     * Creates a [PeopleHubViewModel] that, when clicked, starts an activity using an animation
-     * involving the given [view].
-     */
-    fun createWithAssociatedClickView(view: View): PeopleHubViewModel
-}
-
-/**
- * Wraps a [PeopleHubViewBoundary] in a [DataListener], and connects it to the data
- * pipeline.
- *
- * @param dataSource PeopleHub data pipeline.
- */
-@SysUISingleton
-class PeopleHubViewAdapterImpl @Inject constructor(
-    private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubViewModelFactory>
-) : PeopleHubViewAdapter {
-
-    override fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription =
-            dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary))
-}
-
-private class PeopleHubDataListenerImpl(
-    private val viewBoundary: PeopleHubViewBoundary
-) : DataListener<PeopleHubViewModelFactory> {
-
-    override fun onDataChanged(data: PeopleHubViewModelFactory) {
-        val viewModel = data.createWithAssociatedClickView(
-                viewBoundary.associatedViewForClickAnimation
-        )
-        viewBoundary.setVisible(viewModel.isVisible)
-        val padded = viewModel.people + repeated(null)
-        for ((adapter, model) in viewBoundary.personViewAdapters.zip(padded)) {
-            adapter.onDataChanged(model)
-        }
-    }
-}
-
-/**
- * Converts [PeopleHubModel]s into [PeopleHubViewModelFactory]s.
- *
- * This class serves as the glue between the View layer (which depends on
- * [PeopleHubViewBoundary]) and the Data layer (which produces [PeopleHubModel]s).
- */
-@SysUISingleton
-class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor(
-    private val activityStarter: ActivityStarter,
-    private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubModel>
-) : DataSource<PeopleHubViewModelFactory> {
-
-    override fun registerListener(listener: DataListener<PeopleHubViewModelFactory>): Subscription {
-        var model: PeopleHubModel? = null
-
-        fun updateListener() {
-            // don't invoke listener until we've received our first model
-            model?.let { model ->
-                val factory = PeopleHubViewModelFactoryImpl(model, activityStarter)
-                listener.onDataChanged(factory)
-            }
-        }
-        val dataSub = dataSource.registerListener(object : DataListener<PeopleHubModel> {
-            override fun onDataChanged(data: PeopleHubModel) {
-                model = data
-                updateListener()
-            }
-        })
-        return object : Subscription {
-            override fun unsubscribe() {
-                dataSub.unsubscribe()
-            }
-        }
-    }
-}
-
-private object EmptyViewModelFactory : PeopleHubViewModelFactory {
-    override fun createWithAssociatedClickView(view: View): PeopleHubViewModel {
-        return PeopleHubViewModel(emptySequence(), false)
-    }
-}
-
-private class PeopleHubViewModelFactoryImpl(
-    private val model: PeopleHubModel,
-    private val activityStarter: ActivityStarter
-) : PeopleHubViewModelFactory {
-
-    override fun createWithAssociatedClickView(view: View): PeopleHubViewModel {
-        val personViewModels = model.people.asSequence().map { personModel ->
-            val onClick = {
-                personModel.clickRunnable.run()
-            }
-            PersonViewModel(personModel.name, personModel.avatar, onClick)
-        }
-        return PeopleHubViewModel(personViewModels, model.people.isNotEmpty())
-    }
-}
-
-@SysUISingleton
-class PeopleHubSettingChangeDataSourceImpl @Inject constructor(
-    @Main private val handler: Handler,
-    context: Context
-) : DataSource<Boolean> {
-
-    private val settingUri = Settings.Secure.getUriFor(Settings.Secure.PEOPLE_STRIP)
-    private val contentResolver = context.contentResolver
-
-    override fun registerListener(listener: DataListener<Boolean>): Subscription {
-        // Immediately report current value of setting
-        updateListener(listener)
-        val observer = object : ContentObserver(handler) {
-            override fun onChange(selfChange: Boolean, uri: Uri?, flags: Int) {
-                super.onChange(selfChange, uri, flags)
-                updateListener(listener)
-            }
-        }
-        contentResolver.registerContentObserver(settingUri, false, observer, UserHandle.USER_ALL)
-        return object : Subscription {
-            override fun unsubscribe() = contentResolver.unregisterContentObserver(observer)
-        }
-    }
-
-    private fun updateListener(listener: DataListener<Boolean>) {
-        val setting = Settings.Secure.getIntForUser(
-                contentResolver,
-                Settings.Secure.PEOPLE_STRIP,
-                0,
-                UserHandle.USER_CURRENT
-        )
-        listener.onDataChanged(setting != 0)
-    }
-}
-
-private fun <T> repeated(value: T): Sequence<T> = sequence {
-    while (true) {
-        yield(value)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 855390d..6138265 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -25,8 +25,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -68,6 +66,9 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -3247,6 +3248,7 @@
     }
 
     @Override
+    @NonNull
     public ExpandableViewState createExpandableViewState() {
         return new NotificationViewState();
     }
@@ -3453,6 +3455,8 @@
             pw.print("visibility: " + getVisibility());
             pw.print(", alpha: " + getAlpha());
             pw.print(", translation: " + getTranslation());
+            pw.print(", Entry isDismissable: " + mEntry.isDismissable());
+            pw.print(", mOnUserInteractionCallback null: " + (mOnUserInteractionCallback == null));
             pw.print(", removed: " + isRemoved());
             pw.print(", expandAnimationRunning: " + mExpandAnimationRunning);
             NotificationContentView showingLayout = getShowingLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 8f73b80..1e09b8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -29,6 +29,7 @@
 import android.view.ViewParent;
 import android.widget.FrameLayout;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.systemui.Dumpable;
@@ -66,7 +67,7 @@
     protected float mContentTransformationAmount;
     protected boolean mIsLastChild;
     protected int mContentShift;
-    private final ExpandableViewState mViewState;
+    @NonNull private final ExpandableViewState mViewState;
     private float mContentTranslation;
     protected boolean mLastInSection;
     protected boolean mFirstInSection;
@@ -610,6 +611,7 @@
 
     public void setActualHeightAnimating(boolean animating) {}
 
+    @NonNull
     protected ExpandableViewState createExpandableViewState() {
         return new ExpandableViewState();
     }
@@ -642,7 +644,12 @@
         return mViewState;
     }
 
-    @Nullable public ExpandableViewState getViewState() {
+    /**
+     * Get the {@link ExpandableViewState} associated with the view.
+     *
+     * @return the ExpandableView's view state.
+     */
+    @NonNull public ExpandableViewState getViewState() {
         return mViewState;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
index e43ecf7..49dc655 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/FooterView.java
@@ -23,6 +23,8 @@
 import android.util.IndentingPrintWriter;
 import android.view.View;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
 import com.android.systemui.statusbar.notification.stack.ViewState;
@@ -142,6 +144,7 @@
     }
 
     @Override
+    @NonNull
     public ExpandableViewState createExpandableViewState() {
         return new FooterViewState();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
deleted file mode 100644
index 6abfee9..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
+++ /dev/null
@@ -1,206 +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.statusbar.notification.row;
-
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
-
-import android.content.Context;
-import android.metrics.LogMaker;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
-import com.android.systemui.statusbar.notification.logging.NotificationCounters;
-import com.android.systemui.util.Compile;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Manager for the notification blocking helper - tracks and helps create the blocking helper
- * affordance.
- */
-public class NotificationBlockingHelperManager {
-    /** Enables debug logging and always makes the blocking helper show up after a dismiss. */
-    private static final String TAG = "BlockingHelper";
-    private static final boolean DEBUG = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
-    private static final boolean DEBUG_ALWAYS_SHOW = false;
-
-    private final Context mContext;
-    private final NotificationGutsManager mNotificationGutsManager;
-    private final NotificationEntryManager mNotificationEntryManager;
-    private final MetricsLogger mMetricsLogger;
-    private final GroupMembershipManager mGroupMembershipManager;
-    /** Row that the blocking helper will be shown in (via {@link NotificationGuts}. */
-    private ExpandableNotificationRow mBlockingHelperRow;
-    private Set<String> mNonBlockablePkgs;
-
-    /**
-     * Whether the notification shade/stack is expanded - used to determine blocking helper
-     * eligibility.
-     */
-    private boolean mIsShadeExpanded;
-
-    /**
-     * Injected constructor. See {@link NotificationsModule}.
-     */
-    public NotificationBlockingHelperManager(
-            Context context,
-            NotificationGutsManager notificationGutsManager,
-            NotificationEntryManager notificationEntryManager,
-            MetricsLogger metricsLogger,
-            GroupMembershipManager groupMembershipManager) {
-        mContext = context;
-        mNotificationGutsManager = notificationGutsManager;
-        mNotificationEntryManager = notificationEntryManager;
-        mMetricsLogger = metricsLogger;
-        mNonBlockablePkgs = new HashSet<>();
-        Collections.addAll(mNonBlockablePkgs, mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_nonBlockableNotificationPackages));
-        mGroupMembershipManager = groupMembershipManager;
-    }
-
-    /**
-     * Potentially shows the blocking helper, represented via the {@link NotificationInfo} menu
-     * item, in the current row if user sentiment is negative.
-     *
-     * @param row row to render the blocking helper in
-     * @param menuRow menu used to generate the {@link NotificationInfo} view that houses the
-     *                blocking helper UI
-     * @return whether we're showing a blocking helper in the given notification row
-     */
-    boolean perhapsShowBlockingHelper(
-            ExpandableNotificationRow row, NotificationMenuRowPlugin menuRow) {
-        // We only show the blocking helper if:
-        // - User sentiment is negative (DEBUG flag can bypass)
-        // - The notification shade is fully expanded (guarantees we're not touching a HUN).
-        // - The row is blockable (i.e. not non-blockable)
-        // - The dismissed row is a valid group (>1 or 0 children from the same channel)
-        // or the only child in the group
-        final NotificationEntry entry = row.getEntry();
-        if ((entry.getUserSentiment() == USER_SENTIMENT_NEGATIVE || DEBUG_ALWAYS_SHOW)
-                && mIsShadeExpanded
-                && !row.getIsNonblockable()
-                && ((!row.isChildInGroup() || mGroupMembershipManager.isOnlyChildInGroup(entry))
-                    && row.getNumUniqueChannels() <= 1)) {
-            // Dismiss any current blocking helper before continuing forward (only one can be shown
-            // at a given time).
-            dismissCurrentBlockingHelper();
-
-            if (DEBUG) {
-                Log.d(TAG, "Manager.perhapsShowBlockingHelper: Showing new blocking helper");
-            }
-
-            // Enable blocking helper on the row before moving forward so everything in the guts is
-            // correctly prepped.
-            mBlockingHelperRow = row;
-            mBlockingHelperRow.setBlockingHelperShowing(true);
-
-            // Log triggering of blocking helper by the system. This log line
-            // should be emitted before the "display" log line.
-            mMetricsLogger.write(
-                    getLogMaker().setSubtype(MetricsEvent.BLOCKING_HELPER_TRIGGERED_BY_SYSTEM));
-
-            // We don't care about the touch origin (x, y) since we're opening guts without any
-            // explicit user interaction.
-            mNotificationGutsManager.openGuts(
-                    mBlockingHelperRow, 0, 0, menuRow.getLongpressMenuItem(mContext));
-
-            mMetricsLogger.count(NotificationCounters.BLOCKING_HELPER_SHOWN, 1);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Dismiss the currently showing blocking helper, if any, through a notification update.
-     *
-     * @return whether the blocking helper was dismissed
-     */
-    boolean dismissCurrentBlockingHelper() {
-        if (!isBlockingHelperRowNull()) {
-            if (DEBUG) {
-                Log.d(TAG, "Manager.dismissCurrentBlockingHelper: Dismissing current helper");
-            }
-            if (!mBlockingHelperRow.isBlockingHelperShowing()) {
-                Log.e(TAG, "Manager.dismissCurrentBlockingHelper: "
-                        + "Non-null row is not showing a blocking helper");
-            }
-
-            mBlockingHelperRow.setBlockingHelperShowing(false);
-            if (mBlockingHelperRow.isAttachedToWindow()) {
-                mNotificationEntryManager.updateNotifications("dismissCurrentBlockingHelper");
-            }
-            mBlockingHelperRow = null;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Update the expansion status of the notification shade/stack.
-     *
-     * @param expandedHeight how much the shade is expanded ({code 0} indicating it's collapsed)
-     */
-    public void setNotificationShadeExpanded(float expandedHeight) {
-        mIsShadeExpanded = expandedHeight > 0.0f;
-    }
-
-    /**
-     * Returns whether the given package name is in the list of non-blockable packages.
-     */
-    public boolean isNonblockable(String packageName, String channelName) {
-        return mNonBlockablePkgs.contains(packageName)
-                || mNonBlockablePkgs.contains(makeChannelKey(packageName, channelName));
-    }
-
-    private LogMaker getLogMaker() {
-        return mBlockingHelperRow.getEntry().getSbn()
-            .getLogMaker()
-            .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER);
-    }
-
-    // Format must stay in sync with frameworks/base/core/res/res/values/config.xml
-    // config_nonBlockableNotificationPackages
-    private String makeChannelKey(String pkg, String channel) {
-        return pkg + ":" + channel;
-    }
-
-    @VisibleForTesting
-    boolean isBlockingHelperRowNull() {
-        return mBlockingHelperRow == null;
-    }
-
-    @VisibleForTesting
-    void setBlockingHelperRowForTest(ExpandableNotificationRow blockingHelperRowForTest) {
-        mBlockingHelperRow = blockingHelperRowForTest;
-    }
-
-    @VisibleForTesting
-    void setNonBlockablePkgs(String[] pkgsAndChannels) {
-        mNonBlockablePkgs = new HashSet<>();
-        Collections.addAll(mNonBlockablePkgs, pkgsAndChannels);
-    }
-}
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 79d883b3..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
      *
@@ -4460,8 +4439,7 @@
     }
 
     private void updateVisibility() {
-        boolean shouldShow = !mAmbientState.isFullyHidden() || !onKeyguard();
-        setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE);
+        mController.updateVisibility(!mAmbientState.isFullyHidden() || !onKeyguard());
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4526,17 +4504,21 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    void updateEmptyShadeView(boolean visible, boolean notifVisibleInShade) {
+    void updateEmptyShadeView(boolean visible, boolean areNotificationsHiddenInShade) {
         mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
 
         int oldTextRes = mEmptyShadeView.getTextResource();
-        int newTextRes = notifVisibleInShade
+        int newTextRes = areNotificationsHiddenInShade
                 ? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
         if (oldTextRes != newTextRes) {
             mEmptyShadeView.setText(newTextRes);
         }
     }
 
+    public boolean isEmptyShadeViewVisible() {
+        return mEmptyShadeView.isVisible();
+    }
+
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void updateFooterView(boolean visible, boolean showDismissView, boolean showHistory) {
         if (mFooterView == null) {
@@ -5039,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();
@@ -6116,9 +6098,6 @@
             }
             return row.canViewBeDismissed();
         }
-        if (v instanceof PeopleHubView) {
-            return ((PeopleHubView) v).getCanSwipe();
-        }
         return false;
     }
 
@@ -6130,9 +6109,6 @@
             }
             return row.canViewBeCleared();
         }
-        if (v instanceof PeopleHubView) {
-            return ((PeopleHubView) v).getCanSwipe();
-        }
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 3f6586c..843a9ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -81,14 +81,11 @@
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.PipelineDumpable;
 import com.android.systemui.statusbar.notification.collection.PipelineDumper;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -157,7 +154,6 @@
     private final ScrimController mScrimController;
     private final NotifPipeline mNotifPipeline;
     private final NotifCollection mNotifCollection;
-    private final NotificationEntryManager mNotificationEntryManager;
     private final UiEventLogger mUiEventLogger;
     private final NotificationRemoteInputManager mRemoteInputManager;
     private final ShadeController mShadeController;
@@ -179,7 +175,6 @@
     private NotificationStackScrollLayout mView;
     private boolean mFadeNotificationsOnDismiss;
     private NotificationSwipeHelper mSwipeHelper;
-    private boolean mShowEmptyShadeView;
     @Nullable private Boolean mHistoryEnabled;
     private int mBarState;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
@@ -310,7 +305,6 @@
                     mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
                             mLockscreenUserManager.isAnyProfilePublicMode());
                     mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
-                    mNotificationEntryManager.updateNotifications("CentralSurfaces state changed");
                 }
             };
 
@@ -633,12 +627,10 @@
             NotificationSwipeHelper.Builder notificationSwipeHelperBuilder,
             CentralSurfaces centralSurfaces,
             ScrimController scrimController,
-            NotificationGroupManagerLegacy legacyGroupManager,
             GroupExpansionManager groupManager,
             @SilentHeader SectionHeaderController silentHeaderController,
             NotifPipeline notifPipeline,
             NotifCollection notifCollection,
-            NotificationEntryManager notificationEntryManager,
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
             ShadeTransitionController shadeTransitionController,
             UiEventLogger uiEventLogger,
@@ -677,16 +669,9 @@
         mJankMonitor = jankMonitor;
         mNotificationStackSizeCalculator = notificationStackSizeCalculator;
         mGroupExpansionManager = groupManager;
-        legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
-            @Override
-            public void onGroupsChanged() {
-                mCentralSurfaces.requestNotificationUpdate("onGroupsChanged");
-            }
-        });
         mSilentHeaderController = silentHeaderController;
         mNotifPipeline = notifPipeline;
         mNotifCollection = notifCollection;
-        mNotificationEntryManager = notificationEntryManager;
         mUiEventLogger = uiEventLogger;
         mRemoteInputManager = remoteInputManager;
         mShadeController = shadeController;
@@ -1182,8 +1167,21 @@
     }
 
     /**
-     * Update whether we should show the empty shade view (no notifications in the shade).
-     * If so, send the update to our view.
+     * Set the visibility of the view, and propagate it to specific children.
+     *
+     * @param visible either the view is visible or not.
+     */
+    public void updateVisibility(boolean visible) {
+        mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+
+        if (mView.getVisibility() == View.VISIBLE) {
+            // Synchronize EmptyShadeView visibility with the parent container.
+            updateShowEmptyShadeView();
+        }
+    }
+
+    /**
+     * Update whether we should show the empty shade view ("no notifications" in the shade).
      *
      * When in split mode, notifications are always visible regardless of the state of the
      * QuickSettings panel. That being the case, empty view is always shown if the other conditions
@@ -1191,18 +1189,31 @@
      */
     public void updateShowEmptyShadeView() {
         Trace.beginSection("NSSLC.updateShowEmptyShadeView");
-        mShowEmptyShadeView = mStatusBarStateController.getCurrentOrUpcomingState() != KEYGUARD
-                && !mView.isQsFullScreen()
-                && getVisibleNotificationCount() == 0;
 
-        mView.updateEmptyShadeView(
-                mShowEmptyShadeView,
-                mZenModeController.areNotificationsHiddenInShade());
+        final boolean shouldShow = getVisibleNotificationCount() == 0
+                && !mView.isQsFullScreen()
+                // Hide empty shade view when in transition to Keyguard.
+                // That avoids "No Notifications" to blink when transitioning to AOD.
+                // For more details, see: b/228790482
+                && !isInTransitionToKeyguard();
+
+        mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
+
         Trace.endSection();
     }
 
+    /**
+     * @return true if {@link StatusBarStateController} is in transition to the KEYGUARD
+     *         and false otherwise.
+     */
+    private boolean isInTransitionToKeyguard() {
+        final int currentState = mStatusBarStateController.getState();
+        final int upcomingState = mStatusBarStateController.getCurrentOrUpcomingState();
+        return (currentState != upcomingState && upcomingState == KEYGUARD);
+    }
+
     public boolean isShowingEmptyShadeView() {
-        return mShowEmptyShadeView;
+        return mView.isEmptyShadeViewVisible();
     }
 
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
deleted file mode 100644
index b13e7fb..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.stack
-
-import android.annotation.ColorInt
-import android.content.Context
-import android.util.AttributeSet
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
-import com.android.systemui.R
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin
-import com.android.systemui.statusbar.notification.people.DataListener
-import com.android.systemui.statusbar.notification.people.PersonViewModel
-import com.android.systemui.statusbar.notification.row.StackScrollerDecorView
-
-class PeopleHubView(context: Context, attrs: AttributeSet) :
-        StackScrollerDecorView(context, attrs), SwipeableView {
-
-    private lateinit var contents: ViewGroup
-    private lateinit var label: TextView
-
-    lateinit var personViewAdapters: Sequence<DataListener<PersonViewModel?>>
-        private set
-
-    override fun onFinishInflate() {
-        contents = requireViewById(R.id.people_list)
-        label = requireViewById(R.id.header_label)
-        personViewAdapters = (0 until contents.childCount)
-                .asSequence() // so we can map
-                .mapNotNull { idx ->
-                    // get all our people slots
-                    (contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl)
-                }
-                .toList() // cache it
-                .asSequence() // but don't reveal it's a list
-        super.onFinishInflate()
-        setVisible(true /* nowVisible */, false /* animate */)
-    }
-
-    fun setTextColor(@ColorInt color: Int) = label.setTextColor(color)
-
-    override fun findContentView(): View = contents
-    override fun findSecondaryView(): View? = null
-
-    override fun hasFinishedInitialization(): Boolean = true
-
-    override fun createMenu(): NotificationMenuRowPlugin? = null
-
-    override fun resetTranslation() {
-        translationX = 0f
-    }
-
-    override fun setTranslation(translation: Float) {
-        if (canSwipe) {
-            super.setTranslation(translation)
-        }
-    }
-
-    var canSwipe: Boolean = false
-        set(value) {
-            if (field != value) {
-                if (field) {
-                    resetTranslation()
-                }
-                field = value
-            }
-        }
-
-    override fun needsClippingToShelf(): Boolean = true
-
-    override fun applyContentTransformation(contentAlpha: Float, translationY: Float) {
-        super.applyContentTransformation(contentAlpha, translationY)
-        for (i in 0 until contents.childCount) {
-            val view = contents.getChildAt(i)
-            view.alpha = contentAlpha
-            view.translationY = translationY
-        }
-    }
-
-    fun setOnHeaderClickListener(listener: OnClickListener) = label.setOnClickListener(listener)
-
-    private inner class PersonDataListenerImpl(val avatarView: ImageView) :
-            DataListener<PersonViewModel?> {
-
-        override fun onDataChanged(data: PersonViewModel?) {
-            avatarView.visibility = data?.let { View.VISIBLE } ?: View.GONE
-            avatarView.setImageDrawable(data?.icon)
-            avatarView.setOnClickListener { data?.onClick?.invoke() }
-        }
-    }
-}
\ No newline at end of file
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 6d513d0da..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
@@ -120,11 +120,64 @@
         updateClipping(algorithmState, ambientState);
         updateSpeedBumpState(algorithmState, speedBumpIndex);
         updateShelfState(algorithmState, ambientState);
+        updateAlphaState(algorithmState, ambientState);
         getNotificationChildrenStates(algorithmState, ambientState);
     }
 
+    private void updateAlphaState(StackScrollAlgorithmState algorithmState,
+            AmbientState ambientState) {
+        for (ExpandableView view : algorithmState.visibleChildren) {
+            final ViewState viewState = view.getViewState();
+
+            final boolean isHunGoingToShade = ambientState.isShadeExpanded()
+                    && view == ambientState.getTrackedHeadsUpRow();
+
+            if (isHunGoingToShade) {
+                // Keep 100% opacity for heads up notification going to shade.
+                viewState.alpha = 1f;
+            } else if (ambientState.isOnKeyguard()) {
+                // Adjust alpha for wakeup to lockscreen.
+                viewState.alpha = 1f - ambientState.getHideAmount();
+            } else if (ambientState.isExpansionChanging()) {
+                // Adjust alpha for shade open & close.
+                float expansion = ambientState.getExpansionFraction();
+                viewState.alpha = ambientState.isBouncerInTransit()
+                        ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion)
+                        : ShadeInterpolation.getContentAlpha(expansion);
+            }
+
+            // For EmptyShadeView if on keyguard, we need to control the alpha to create
+            // a nice transition when the user is dragging down the notification panel.
+            if (view instanceof EmptyShadeView && ambientState.isOnKeyguard()) {
+                final float fractionToShade = ambientState.getFractionToShade();
+                viewState.alpha = ShadeInterpolation.getContentAlpha(fractionToShade);
+            }
+
+            NotificationShelf shelf = ambientState.getShelf();
+            if (shelf != null) {
+                final ViewState shelfState = shelf.getViewState();
+
+                // After the shelf has updated its yTranslation, explicitly set alpha=0 for view
+                // below shelf to skip rendering them in the hardware layer. We do not set them
+                // invisible because that runs invalidate & onDraw when these views return onscreen,
+                // which is more expensive.
+                if (shelfState.hidden) {
+                    // When the shelf is hidden, it won't clip views, so we don't hide rows
+                    continue;
+                }
+
+                final float shelfTop = shelfState.yTranslation;
+                final float viewTop = viewState.yTranslation;
+                if (viewTop >= shelfTop) {
+                    viewState.alpha = 0;
+                }
+            }
+        }
+    }
+
     /**
      * How expanded or collapsed notifications are when pulling down the shade.
+     *
      * @param ambientState Current ambient state.
      * @return 0 when fully collapsed, 1 when expanded.
      */
@@ -208,22 +261,6 @@
         }
 
         shelf.updateState(algorithmState, ambientState);
-
-        // After the shelf has updated its yTranslation, explicitly set alpha=0 for view below shelf
-        // to skip rendering them in the hardware layer. We do not set them invisible because that
-        // runs invalidate & onDraw when these views return onscreen, which is more expensive.
-        if (shelf.getViewState().hidden) {
-            // When the shelf is hidden, it won't clip views, so we don't hide rows
-            return;
-        }
-        final float shelfTop = shelf.getViewState().yTranslation;
-
-        for (ExpandableView view : algorithmState.visibleChildren) {
-            final float viewTop = view.getViewState().yTranslation;
-            if (viewTop >= shelfTop) {
-                view.getViewState().alpha = 0;
-            }
-        }
     }
 
     private void updateClipping(StackScrollAlgorithmState algorithmState,
@@ -473,21 +510,6 @@
         ExpandableViewState viewState = view.getViewState();
         viewState.location = ExpandableViewState.LOCATION_UNKNOWN;
 
-        final boolean isHunGoingToShade = ambientState.isShadeExpanded()
-                && view == ambientState.getTrackedHeadsUpRow();
-        if (isHunGoingToShade) {
-            // Keep 100% opacity for heads up notification going to shade.
-        } else if (ambientState.isOnKeyguard()) {
-            // Adjust alpha for wakeup to lockscreen.
-            viewState.alpha = 1f - ambientState.getHideAmount();
-        } else if (ambientState.isExpansionChanging()) {
-            // Adjust alpha for shade open & close.
-            float expansion = ambientState.getExpansionFraction();
-            viewState.alpha = ambientState.isBouncerInTransit()
-                    ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion)
-                    : ShadeInterpolation.getContentAlpha(expansion);
-        }
-
         final float expansionFraction = getExpansionFractionWithoutShelf(
                 algorithmState, ambientState);
 
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 7bef844..0b2d443 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -28,11 +28,8 @@
 import android.metrics.LogMaker;
 import android.os.Handler;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.SystemClock;
 import android.os.Trace;
-import android.os.VibrationAttributes;
-import android.os.VibrationEffect;
 import android.util.Log;
 
 import androidx.annotation.Nullable;
@@ -55,14 +52,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;
@@ -88,12 +82,6 @@
     private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
     private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
     private static final int UDFPS_ATTEMPTS_BEFORE_SHOW_BOUNCER = 3;
-    private static final VibrationEffect SUCCESS_VIBRATION_EFFECT =
-            VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
-    private static final VibrationEffect ERROR_VIBRATION_EFFECT =
-            VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
-    private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
-            VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
 
     @IntDef(prefix = { "MODE_" }, value = {
             MODE_NONE,
@@ -162,14 +150,12 @@
     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;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final SessionTracker mSessionTracker;
     private final int mConsecutiveFpFailureThreshold;
-    private final boolean mShouldVibrate;
     private int mMode;
     private BiometricSourceType mBiometricType;
     private KeyguardViewController mKeyguardViewController;
@@ -177,7 +163,6 @@
     private KeyguardViewMediator mKeyguardViewMediator;
     private ScrimController mScrimController;
     private PendingAuthenticated mPendingAuthenticated = null;
-    private boolean mPendingShowBouncer;
     private boolean mHasScreenTurnedOnSinceAuthenticating;
     private boolean mFadedAwayAfterWakeAndUnlock;
     private BiometricModeListener mBiometricModeListener;
@@ -269,13 +254,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,
@@ -288,13 +271,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);
@@ -311,14 +292,11 @@
         mHandler = handler;
         mConsecutiveFpFailureThreshold = resources.getInteger(
                 R.integer.fp_consecutive_failure_time_ms);
-        mShouldVibrate = !(resources.getBoolean(
-                com.android.internal.R.bool.system_server_plays_face_haptics));
         mKeyguardBypassController = keyguardBypassController;
         mKeyguardBypassController.setUnlockController(this);
         mMetricsLogger = metricsLogger;
         mAuthController = authController;
         mStatusBarStateController = statusBarStateController;
-        mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
         mSessionTracker = sessionTracker;
         mScreenOffAnimationController = screenOffAnimationController;
         mVibratorHelper = vibrator;
@@ -427,10 +405,10 @@
     public void startWakeAndUnlock(BiometricSourceType biometricSourceType,
                                    boolean isStrongBiometric) {
         int mode = calculateMode(biometricSourceType, isStrongBiometric);
-        if (BiometricSourceType.FACE == biometricSourceType && (mode == MODE_WAKE_AND_UNLOCK
+        if (mode == MODE_WAKE_AND_UNLOCK
                 || mode == MODE_WAKE_AND_UNLOCK_PULSING || mode == MODE_UNLOCK_COLLAPSING
-                || mode == MODE_WAKE_AND_UNLOCK_FROM_DREAM || mode == MODE_DISMISS_BOUNCER)) {
-            vibrateSuccess();
+                || mode == MODE_WAKE_AND_UNLOCK_FROM_DREAM || mode == MODE_DISMISS_BOUNCER) {
+            vibrateSuccess(biometricSourceType);
         }
         startWakeAndUnlock(mode);
     }
@@ -474,22 +452,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:
@@ -527,15 +496,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
@@ -672,10 +632,11 @@
         }
 
         // Suppress all face auth errors if fingerprint can be used to authenticate
-        if (biometricSourceType == BiometricSourceType.FACE
+        if ((biometricSourceType == BiometricSourceType.FACE
                 && !mUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                KeyguardUpdateMonitor.getCurrentUser())) {
-            vibrateError();
+                KeyguardUpdateMonitor.getCurrentUser()))
+                || (biometricSourceType == BiometricSourceType.FINGERPRINT)) {
+            vibrateError(biometricSourceType);
         }
 
         cleanup();
@@ -704,24 +665,15 @@
         cleanup();
     }
 
-    private void vibrateSuccess() {
-        if (mShouldVibrate) {
-            mVibratorHelper.vibrate(Process.myUid(),
-                    "com.android.systemui",
-                    SUCCESS_VIBRATION_EFFECT,
-                    getClass().getSimpleName() + "::success",
-                    HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
-        }
+    //these haptics are for device-entry only
+    private void vibrateSuccess(BiometricSourceType type) {
+        mVibratorHelper.vibrateAuthSuccess(
+                getClass().getSimpleName() + ", type =" + type + "device-entry::success");
     }
 
-    private void vibrateError() {
-        if (mShouldVibrate) {
-            mVibratorHelper.vibrate(Process.myUid(),
-                    "com.android.systemui",
-                    ERROR_VIBRATION_EFFECT,
-                    getClass().getSimpleName() + "::error",
-                    HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
-        }
+    private void vibrateError(BiometricSourceType type) {
+        mVibratorHelper.vibrateAuthError(
+                getClass().getSimpleName() + ", type =" + type + "device-entry::error");
     }
 
     private void cleanup() {
@@ -762,13 +714,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 602971a..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,8 @@
 
 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;
 import com.android.systemui.animation.RemoteTransitionAdapter;
@@ -219,15 +221,21 @@
 
     ViewGroup getBouncerContainer();
 
+    /** Get the Keyguard Message Area that displays auth messages. */
+    AuthKeyguardMessageArea getKeyguardMessageArea();
+
     int getStatusBarHeight();
 
     void updateQsExpansionEnabled();
 
     boolean isShadeDisabled();
 
-    void requestNotificationUpdate(String reason);
-
-    void requestFaceAuth(boolean userInitiatedRequest);
+    /**
+     * Request face auth to initiated
+     * @param userInitiatedRequest Whether this was a user initiated request
+     * @param reason Reason why face auth was triggered.
+     */
+    void requestFaceAuth(boolean userInitiatedRequest, @FaceAuthApiRequestReason String reason);
 
     @Override
     void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
@@ -386,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/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index 747c4de..e30bc68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -55,12 +55,11 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.qs.QSPanelController;
-import com.android.systemui.shade.NotificationPanelView;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.DisableFlagsLogger;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -326,12 +325,12 @@
                 mNotificationPanelViewController.expand(true /* animate */);
                 mNotificationStackScrollLayoutController.setWillExpand(true);
                 mHeadsUpManager.unpinAll(true /* userUnpinned */);
-                mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN, 1);
+                mMetricsLogger.count("panel_open", 1);
             } else if (!mNotificationPanelViewController.isInSettings()
                     && !mNotificationPanelViewController.isExpanding()) {
                 mNotificationPanelViewController.flingSettings(0 /* velocity */,
-                        NotificationPanelView.FLING_EXPAND);
-                mMetricsLogger.count(NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
+                        NotificationPanelViewController.FLING_EXPAND);
+                mMetricsLogger.count("panel_open_qs", 1);
             }
         }
 
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 cb2ca51..7463dac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -31,8 +31,7 @@
 import static androidx.lifecycle.Lifecycle.State.RESUMED;
 
 import static com.android.systemui.Dependency.TIME_TICK_HANDLER_NAME;
-import static com.android.systemui.charging.WirelessChargingRippleControllerKt.DEFAULT_DURATION;
-import static com.android.systemui.charging.WirelessChargingRippleControllerKt.UNKNOWN_BATTERY_LEVEL;
+import static com.android.systemui.charging.WirelessChargingAnimation.UNKNOWN_BATTERY_LEVEL;
 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP;
 import static com.android.systemui.statusbar.NotificationLockscreenUserManager.PERMISSION_SELF;
 import static com.android.systemui.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT;
@@ -120,6 +119,8 @@
 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;
 import com.android.keyguard.ViewMediatorCallback;
@@ -139,8 +140,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.camera.CameraIntents;
 import com.android.systemui.charging.WiredChargingRippleController;
-import com.android.systemui.charging.WirelessChargingRippleController;
-import com.android.systemui.charging.WirelessChargingView;
+import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.SysUISingleton;
@@ -203,7 +203,6 @@
 import com.android.systemui.statusbar.core.StatusBarInitializer;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -493,7 +492,6 @@
 
     private boolean mExpandedVisible;
 
-    protected final NotificationEntryManager mEntryManager;
     private final NotificationGutsManager mGutsManager;
     private final NotificationLogger mNotificationLogger;
     private final PanelExpansionStateManager mPanelExpansionStateManager;
@@ -509,7 +507,6 @@
     private final WallpaperManager mWallpaperManager;
 
     private CentralSurfacesComponent mCentralSurfacesComponent;
-    private WirelessChargingRippleController mWirelessChargingRippleController;
 
     // Flags for disabling the status bar
     // Two variables becaseu the first one evidently ran out of room for new flags.
@@ -667,7 +664,6 @@
             FalsingManager falsingManager,
             FalsingCollector falsingCollector,
             BroadcastDispatcher broadcastDispatcher,
-            NotificationEntryManager notificationEntryManager,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
             NotificationInterruptStateProvider notificationInterruptStateProvider,
@@ -735,7 +731,6 @@
             InteractionJankMonitor jankMonitor,
             DeviceStateManager deviceStateManager,
             WiredChargingRippleController wiredChargingRippleController,
-            WirelessChargingRippleController wirelessChargingRippleController,
             IDreamManager dreamManager) {
         super(context);
         mNotificationsController = notificationsController;
@@ -755,7 +750,6 @@
         mFalsingCollector = falsingCollector;
         mFalsingManager = falsingManager;
         mBroadcastDispatcher = broadcastDispatcher;
-        mEntryManager = notificationEntryManager;
         mGutsManager = notificationGutsManager;
         mNotificationLogger = notificationLogger;
         mNotificationInterruptStateProvider = notificationInterruptStateProvider;
@@ -826,11 +820,8 @@
 
         mPanelExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged);
 
-        mBubbleExpandListener =
-                (isExpanding, key) -> mContext.getMainExecutor().execute(() -> {
-                    mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
-                    updateScrimController();
-                });
+        mBubbleExpandListener = (isExpanding, key) ->
+                mContext.getMainExecutor().execute(this::updateScrimController);
 
         mActivityIntentHelper = new ActivityIntentHelper(mContext);
         mActivityLaunchAnimator = activityLaunchAnimator;
@@ -853,7 +844,6 @@
         deviceStateManager.registerCallback(mMainExecutor,
                 new FoldStateListener(mContext, this::onFoldedStateChanged));
         wiredChargingRippleController.registerCallbacks();
-        mWirelessChargingRippleController = wirelessChargingRippleController;
     }
 
     @Override
@@ -1576,6 +1566,11 @@
     }
 
     @Override
+    public AuthKeyguardMessageArea getKeyguardMessageArea() {
+        return mNotificationShadeWindowViewController.getKeyguardMessageArea();
+    }
+
+    @Override
     public int getStatusBarHeight() {
         return mStatusBarWindowController.getStatusBarHeight();
     }
@@ -1603,21 +1598,14 @@
     }
 
     /**
-     * Request a notification update
-     * @param reason why we're requesting a notification update
-     */
-    @Override
-    public void requestNotificationUpdate(String reason) {
-        mNotificationsController.requestNotificationUpdate(reason);
-    }
-
-    /**
      * Asks {@link KeyguardUpdateMonitor} to run face auth.
      */
     @Override
-    public void requestFaceAuth(boolean userInitiatedRequest) {
+    public void requestFaceAuth(boolean userInitiatedRequest,
+            @FaceAuthApiRequestReason String reason) {
         if (!mKeyguardStateController.canDismissLockScreen()) {
-            mKeyguardUpdateMonitor.requestFaceAuth(userInitiatedRequest);
+            mKeyguardUpdateMonitor.requestFaceAuth(
+                    userInitiatedRequest, reason);
         }
     }
 
@@ -2167,11 +2155,9 @@
 
     protected void showChargingAnimation(int batteryLevel, int transmittingBatteryLevel,
             long animationDelay) {
-        WirelessChargingView wirelessChargingView = WirelessChargingView.create(mContext,
-                transmittingBatteryLevel, batteryLevel, /* isDozing= */ false,
-                RippleShape.CIRCLE, DEFAULT_DURATION);
-        mWirelessChargingRippleController.show(wirelessChargingView, animationDelay,
-                new WirelessChargingRippleController.Callback() {
+        WirelessChargingAnimation.makeWirelessChargingAnimation(mContext, null,
+                transmittingBatteryLevel, batteryLevel,
+                new WirelessChargingAnimation.Callback() {
                     @Override
                     public void onAnimationStarting() {
                         mNotificationShadeWindowController.setRequestTopUi(true, TAG);
@@ -2181,7 +2167,8 @@
                     public void onAnimationEnded() {
                         mNotificationShadeWindowController.setRequestTopUi(false, TAG);
                     }
-                });
+                }, /* isDozing= */ false, RippleShape.CIRCLE,
+                sUiEventLogger).show(animationDelay);
     }
 
     @Override
@@ -2314,8 +2301,6 @@
             mStatusBarKeyguardViewManager.dump(pw);
         }
 
-        mNotificationsController.dump(pw, args, DUMPTRUCK);
-
         if (DEBUG_GESTURES) {
             pw.print("  status bar gestures: ");
             mGestureRec.dump(pw, args);
@@ -3020,19 +3005,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
@@ -3321,14 +3293,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 */);
             }
         }
@@ -4219,14 +4189,6 @@
                         maybeEscalateHeadsUp();
                     }
                 }
-
-                // TODO: (b/145659174) remove when moving to NewNotifPipeline. Replaced by
-                //  KeyguardCoordinator
-                @Override
-                public void onStrongAuthStateChanged(int userId) {
-                    super.onStrongAuthStateChanged(userId);
-                    mNotificationsController.requestNotificationUpdate("onStrongAuthStateChanged");
-                }
             };
 
 
@@ -4415,7 +4377,6 @@
                     updateQsExpansionEnabled();
                     mKeyguardViewMediator.setDozing(mDozing);
 
-                    mNotificationsController.requestNotificationUpdate("onDozingChanged");
                     updateDozingState();
                     mDozeServiceHost.updateDozing();
                     updateScrimController();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index deb6150..1169d3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
@@ -29,13 +31,13 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.R;
 import com.android.systemui.demomode.DemoMode;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
 import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 
@@ -49,7 +51,6 @@
     private final LinearLayout mStatusIcons;
     private final ArrayList<StatusBarMobileView> mMobileViews = new ArrayList<>();
     private final int mIconSize;
-    private final FeatureFlags mFeatureFlags;
 
     private StatusBarWifiView mWifiView;
     private boolean mDemoMode;
@@ -57,14 +58,12 @@
 
     public DemoStatusIcons(
             LinearLayout statusIcons,
-            int iconSize,
-            FeatureFlags featureFlags
+            int iconSize
     ) {
         super(statusIcons.getContext());
         mStatusIcons = statusIcons;
         mIconSize = iconSize;
         mColor = DarkIconDispatcher.DEFAULT_ICON_TINT;
-        mFeatureFlags = featureFlags;
 
         if (statusIcons instanceof StatusIconContainer) {
             setShouldRestrictIcons(((StatusIconContainer) statusIcons).isRestrictingIcons());
@@ -253,9 +252,13 @@
         }
     }
 
-    public void addMobileView(MobileIconState state) {
+    /**
+     * Add a new mobile icon view
+     */
+    public void addMobileView(MobileIconState state, Context mobileContext) {
         Log.d(TAG, "addMobileView: ");
-        StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, state.slot);
+        StatusBarMobileView view = StatusBarMobileView
+                .fromContext(mobileContext, state.slot);
 
         view.applyMobileState(state);
         view.setStaticDrawableColor(mColor);
@@ -265,19 +268,24 @@
         addView(view, getChildCount(), createLayoutParams());
     }
 
-    public void updateMobileState(MobileIconState state) {
-        Log.d(TAG, "updateMobileState: ");
-        // If the view for this subId exists already, use it
+    /**
+     * Apply an update to a mobile icon view for the given {@link MobileIconState}. For
+     * compatibility with {@link MobileContextProvider}, we have to recreate the view every time we
+     * update it, since the context (and thus the {@link Configuration}) may have changed
+     */
+    public void updateMobileState(MobileIconState state, Context mobileContext) {
+        Log.d(TAG, "updateMobileState: " + state);
+
+        // The mobile config provided by MobileContextProvider could have changed; always recreate
         for (int i = 0; i < mMobileViews.size(); i++) {
             StatusBarMobileView view = mMobileViews.get(i);
             if (view.getState().subId == state.subId) {
-                view.applyMobileState(state);
-                return;
+                removeView(view);
             }
         }
 
-        // Else we have to add it
-        addMobileView(state);
+        // Add the replacement or new icon
+        addMobileView(state, mobileContext);
     }
 
     public void onRemoveIcon(StatusIconDisplayable view) {
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 80c3e6c..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,11 +218,10 @@
             dozing = false;
         }
 
-        mStatusBarStateController.setIsDozing(dozing);
-        mNotificationShadeWindowViewController.setDozing(dozing);
-        if (mFoldAodAnimationController != null) {
-            mFoldAodAnimationController.setIsDozing(dozing);
+        for (Callback callback : mCallbacks) {
+            callback.onDozingChanged(dozing);
         }
+        mStatusBarStateController.setIsDozing(dozing);
     }
 
     @Override
@@ -310,7 +302,6 @@
     public void dozeTimeTick() {
         mNotificationPanel.dozeTimeTick();
         mAuthController.dozeTimeTick();
-        mNotificationShadeWindowViewController.dozeTimeTick();
         if (mAmbientIndicationContainer instanceof DozeReceiver) {
             ((DozeReceiver) mAmbientIndicationContainer).dozeTimeTick();
         }
@@ -454,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/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/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
deleted file mode 100644
index 2c4fc6c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ /dev/null
@@ -1,60 +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.statusbar.phone;
-
-import static com.android.systemui.statusbar.phone.CentralSurfaces.DEBUG;
-import static com.android.systemui.statusbar.phone.CentralSurfaces.MULTIUSER_DEBUG;
-
-import android.service.notification.StatusBarNotification;
-import android.util.Log;
-
-import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-
-import javax.inject.Inject;
-
-@SysUISingleton
-public class KeyguardEnvironmentImpl implements KeyguardEnvironment {
-
-    private static final String TAG = "KeyguardEnvironmentImpl";
-
-    private final NotificationLockscreenUserManager mLockscreenUserManager;
-    private final DeviceProvisionedController mDeviceProvisionedController;
-
-    @Inject
-    public KeyguardEnvironmentImpl(
-            NotificationLockscreenUserManager notificationLockscreenUserManager,
-            DeviceProvisionedController deviceProvisionedController) {
-        mLockscreenUserManager = notificationLockscreenUserManager;
-        mDeviceProvisionedController = deviceProvisionedController;
-    }
-
-    @Override  // NotificationEntryManager.KeyguardEnvironment
-    public boolean isDeviceProvisioned() {
-        return mDeviceProvisionedController.isDeviceProvisioned();
-    }
-
-    @Override  // NotificationEntryManager.KeyguardEnvironment
-    public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
-        final int notificationUserId = n.getUserId();
-        if (DEBUG && MULTIUSER_DEBUG) {
-            Log.v(TAG, String.format("%s: current userid: %d, notification userid: %d", n,
-                    mLockscreenUserManager.getCurrentUserId(), notificationUserId));
-        }
-        return mLockscreenUserManager.isCurrentProfile(notificationUserId);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 3f8e97f1..b58dbe2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -22,6 +22,7 @@
 import android.hardware.TriggerEvent
 import android.hardware.TriggerEventListener
 import com.android.keyguard.ActiveUnlockConfig
+import com.android.keyguard.FaceAuthApiRequestReason
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.CoreStartable
@@ -71,7 +72,10 @@
             // Not listening anymore since trigger events unregister themselves
             isListening = false
             updateListeningState()
-            keyguardUpdateMonitor.requestFaceAuth(true)
+            keyguardUpdateMonitor.requestFaceAuth(
+                true,
+                FaceAuthApiRequestReason.PICK_UP_GESTURE_TRIGGERED
+            )
             keyguardUpdateMonitor.requestActiveUnlock(
                 ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE,
                 "KeyguardLiftController")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index f06b346..ce2c9c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
+import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
+
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 
 import android.animation.Animator;
@@ -43,8 +46,10 @@
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.disableflags.DisableStateTracker;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
@@ -108,6 +113,7 @@
     private final StatusBarUserSwitcherController mUserSwitcherController;
     private final StatusBarUserInfoTracker mStatusBarUserInfoTracker;
     private final SecureSettings mSecureSettings;
+    private final CommandQueue mCommandQueue;
     private final Executor mMainExecutor;
     private final Object mLock = new Object();
 
@@ -218,6 +224,9 @@
                 }
             };
 
+
+    private final DisableStateTracker mDisableStateTracker;
+
     private final List<String> mBlockedIcons = new ArrayList<>();
     private final int mNotificationsHeaderCollideDistance;
 
@@ -269,6 +278,7 @@
             StatusBarUserSwitcherController userSwitcherController,
             StatusBarUserInfoTracker statusBarUserInfoTracker,
             SecureSettings secureSettings,
+            CommandQueue commandQueue,
             @Main Executor mainExecutor
     ) {
         super(view);
@@ -292,6 +302,7 @@
         mUserSwitcherController = userSwitcherController;
         mStatusBarUserInfoTracker = statusBarUserInfoTracker;
         mSecureSettings = secureSettings;
+        mCommandQueue = commandQueue;
         mMainExecutor = mainExecutor;
 
         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
@@ -316,6 +327,12 @@
                 !mFeatureController.isStatusBarUserSwitcherFeatureEnabled());
         mFeatureController.addCallback(enabled -> mView.setKeyguardUserAvatarEnabled(!enabled));
         mSystemEventAnimator = new StatusBarSystemEventAnimator(mView, r);
+
+        mDisableStateTracker = new DisableStateTracker(
+                /* mask1= */ DISABLE_SYSTEM_INFO,
+                /* mask2= */ DISABLE2_SYSTEM_ICONS,
+                this::updateViewState
+        );
     }
 
     @Override
@@ -333,6 +350,7 @@
         mUserInfoController.addCallback(mOnUserInfoChangedListener);
         mStatusBarStateController.addCallback(mStatusBarStateListener);
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
+        mDisableStateTracker.startTracking(mCommandQueue, mView.getDisplay().getDisplayId());
         if (mTintedIconManager == null) {
             mTintedIconManager =
                     mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
@@ -357,6 +375,7 @@
         mUserInfoController.removeCallback(mOnUserInfoChangedListener);
         mStatusBarStateController.removeCallback(mStatusBarStateListener);
         mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
+        mDisableStateTracker.stopTracking(mCommandQueue);
         mSecureSettings.unregisterContentObserver(mVolumeSettingObserver);
         if (mTintedIconManager != null) {
             mStatusBarIconController.removeIconGroup(mTintedIconManager);
@@ -411,6 +430,10 @@
 
     /** Animate the keyguard status bar in. */
     public void animateKeyguardStatusBarIn() {
+        if (mDisableStateTracker.isDisabled()) {
+            // If our view is disabled, don't allow us to animate in.
+            return;
+        }
         mView.setVisibility(View.VISIBLE);
         mView.setAlpha(0f);
         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
@@ -463,7 +486,11 @@
         boolean hideForBypass =
                 mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
                         || mDelayShowingKeyguardStatusBar;
-        int newVisibility = newAlpha != 0f && !mDozing && !hideForBypass
+        int newVisibility =
+                newAlpha != 0f
+                        && !mDozing
+                        && !hideForBypass
+                        && !mDisableStateTracker.isDisabled()
                 ? View.VISIBLE : View.INVISIBLE;
 
         updateViewState(newAlpha, newVisibility);
@@ -473,6 +500,9 @@
      * Updates the {@link KeyguardStatusBarView} state based on the provided values.
      */
     public void updateViewState(float alpha, int visibility) {
+        if (mDisableStateTracker.isDisabled()) {
+            visibility = View.INVISIBLE;
+        }
         mView.setAlpha(alpha);
         mView.setVisibility(visibility);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 290df3e..48e58fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
 import android.content.res.Resources;
 import android.media.AudioManager;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -127,7 +128,7 @@
     private final DateFormatUtil mDateFormatUtil;
     private final TelecomManager mTelecomManager;
 
-    private final Handler mHandler = new Handler();
+    private final Handler mHandler;
     private final CastController mCast;
     private final HotspotController mHotspot;
     private final NextAlarmController mNextAlarmController;
@@ -166,7 +167,7 @@
     @Inject
     public PhoneStatusBarPolicy(StatusBarIconController iconController,
             CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher,
-            @UiBackground Executor uiBgExecutor, @Main Resources resources,
+            @UiBackground Executor uiBgExecutor, @Main Looper looper, @Main Resources resources,
             CastController castController, HotspotController hotspotController,
             BluetoothController bluetoothController, NextAlarmController nextAlarmController,
             UserInfoController userInfoController, RotationLockController rotationLockController,
@@ -185,6 +186,7 @@
         mIconController = iconController;
         mCommandQueue = commandQueue;
         mBroadcastDispatcher = broadcastDispatcher;
+        mHandler = new Handler(looper);
         mResources = resources;
         mCast = castController;
         mHotspot = hotspotController;
@@ -332,6 +334,7 @@
         mRotationLockController.addCallback(this);
         mBluetooth.addCallback(this);
         mProvisionedController.addCallback(this);
+        mCurrentUserSetup = mProvisionedController.isCurrentUserSetup();
         mZenController.addCallback(this);
         mCast.addCallback(mCastCallback);
         mHotspot.addCallback(mHotspotCallback);
@@ -562,6 +565,7 @@
                     mHandler.post(() -> {
                         updateAlarm();
                         updateManagedProfile();
+                        onUserSetupChanged();
                     });
                 }
             };
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/StatusBarHeadsUpChangeListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
index ebfbf54..ae201e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -120,7 +120,6 @@
 
     @Override
     public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
         if (mStatusBarStateController.isDozing() && isHeadsUp) {
             entry.setPulseSuppressed(false);
             mDozeServiceHost.fireNotificationPulse(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index ed186ab..bd99713 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -33,11 +33,9 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.demomode.DemoModeCommandReceiver;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
 import com.android.systemui.statusbar.BaseStatusBarWifiView;
@@ -45,6 +43,7 @@
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
 import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
@@ -71,6 +70,7 @@
     void addIconGroup(IconManager iconManager);
     /** */
     void removeIconGroup(IconManager iconManager);
+
     /** Refresh the state of an IconManager by recreating the views */
     void refreshIconGroup(IconManager iconManager);
     /** */
@@ -83,21 +83,25 @@
     void setSignalIcon(String slot, WifiIconState state);
     /** */
     void setMobileIcons(String slot, List<MobileIconState> states);
+
     /**
      * Display the no calling & SMS icons.
      */
     void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
+
     /**
      * Display the no calling & SMS icons.
      */
     void setNoCallingIcons(String slot, List<CallIndicatorIconState> states);
+
     public void setIconVisibility(String slot, boolean b);
 
     /**
      * Sets the live region mode for the icon
-     * @see android.view.View#setAccessibilityLiveRegion(int)
-     * @param slot Icon slot to set region for
+     *
+     * @param slot                    Icon slot to set region for
      * @param accessibilityLiveRegion live region mode for the icon
+     * @see android.view.View#setAccessibilityLiveRegion(int)
      */
     void setIconAccessibilityLiveRegion(String slot, int accessibilityLiveRegion);
 
@@ -116,8 +120,8 @@
     static ArraySet<String> getIconHideList(Context context, String hideListStr) {
         ArraySet<String> ret = new ArraySet<>();
         String[] hideList = hideListStr == null
-            ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
-            : hideListStr.split(",");
+                ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
+                : hideListStr.split(",");
         for (String slot : hideList) {
             if (!TextUtils.isEmpty(slot)) {
                 ret.add(slot);
@@ -135,13 +139,17 @@
 
         public DarkIconManager(
                 LinearLayout linearLayout,
-                FeatureFlags featureFlags,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider) {
-            super(linearLayout, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
+                Provider<WifiViewModel> wifiViewModelProvider,
+                MobileContextProvider mobileContextProvider,
+                DarkIconDispatcher darkIconDispatcher) {
+            super(linearLayout,
+                    statusBarPipelineFlags,
+                    wifiViewModelProvider,
+                    mobileContextProvider);
             mIconHPadding = mContext.getResources().getDimensionPixelSize(
                     R.dimen.status_bar_icon_padding);
-            mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
+            mDarkIconDispatcher = darkIconDispatcher;
         }
 
         @Override
@@ -195,37 +203,49 @@
 
         @SysUISingleton
         public static class Factory {
-            private final FeatureFlags mFeatureFlags;
             private final StatusBarPipelineFlags mStatusBarPipelineFlags;
             private final Provider<WifiViewModel> mWifiViewModelProvider;
+            private final MobileContextProvider mMobileContextProvider;
+            private final DarkIconDispatcher mDarkIconDispatcher;
 
             @Inject
             public Factory(
-                    FeatureFlags featureFlags,
                     StatusBarPipelineFlags statusBarPipelineFlags,
-                    Provider<WifiViewModel> wifiViewModelProvider) {
-                mFeatureFlags = featureFlags;
+                    Provider<WifiViewModel> wifiViewModelProvider,
+                    MobileContextProvider mobileContextProvider,
+                    DarkIconDispatcher darkIconDispatcher) {
                 mStatusBarPipelineFlags = statusBarPipelineFlags;
                 mWifiViewModelProvider = wifiViewModelProvider;
+                mMobileContextProvider = mobileContextProvider;
+                mDarkIconDispatcher = darkIconDispatcher;
             }
 
             public DarkIconManager create(LinearLayout group) {
                 return new DarkIconManager(
-                        group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider);
+                        group,
+                        mStatusBarPipelineFlags,
+                        mWifiViewModelProvider,
+                        mMobileContextProvider,
+                        mDarkIconDispatcher);
             }
         }
     }
 
-    /** */
+    /**
+     *
+     */
     class TintedIconManager extends IconManager {
         private int mColor;
 
         public TintedIconManager(
                 ViewGroup group,
-                FeatureFlags featureFlags,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider) {
-            super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
+                Provider<WifiViewModel> wifiViewModelProvider,
+                MobileContextProvider mobileContextProvider) {
+            super(group,
+                    statusBarPipelineFlags,
+                    wifiViewModelProvider,
+                    mobileContextProvider);
         }
 
         @Override
@@ -257,23 +277,26 @@
 
         @SysUISingleton
         public static class Factory {
-            private final FeatureFlags mFeatureFlags;
             private final StatusBarPipelineFlags mStatusBarPipelineFlags;
             private final Provider<WifiViewModel> mWifiViewModelProvider;
+            private final MobileContextProvider mMobileContextProvider;
 
             @Inject
             public Factory(
-                    FeatureFlags featureFlags,
                     StatusBarPipelineFlags statusBarPipelineFlags,
-                    Provider<WifiViewModel> wifiViewModelProvider) {
-                mFeatureFlags = featureFlags;
+                    Provider<WifiViewModel> wifiViewModelProvider,
+                    MobileContextProvider mobileContextProvider) {
                 mStatusBarPipelineFlags = statusBarPipelineFlags;
                 mWifiViewModelProvider = wifiViewModelProvider;
+                mMobileContextProvider = mobileContextProvider;
             }
 
             public TintedIconManager create(ViewGroup group) {
                 return new TintedIconManager(
-                        group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider);
+                        group,
+                        mStatusBarPipelineFlags,
+                        mWifiViewModelProvider,
+                        mMobileContextProvider);
             }
         }
     }
@@ -283,9 +306,9 @@
      */
     class IconManager implements DemoModeCommandReceiver {
         protected final ViewGroup mGroup;
-        private final FeatureFlags mFeatureFlags;
         private final StatusBarPipelineFlags mStatusBarPipelineFlags;
         private final Provider<WifiViewModel> mWifiViewModelProvider;
+        private final MobileContextProvider mMobileContextProvider;
         protected final Context mContext;
         protected final int mIconSize;
         // Whether or not these icons show up in dumpsys
@@ -301,13 +324,13 @@
 
         public IconManager(
                 ViewGroup group,
-                FeatureFlags featureFlags,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider) {
+                Provider<WifiViewModel> wifiViewModelProvider,
+                MobileContextProvider mobileContextProvider) {
             mGroup = group;
-            mFeatureFlags = featureFlags;
             mStatusBarPipelineFlags = statusBarPipelineFlags;
             mWifiViewModelProvider = wifiViewModelProvider;
+            mMobileContextProvider = mobileContextProvider;
             mContext = group.getContext();
             mIconSize = mContext.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.status_bar_icon_size);
@@ -399,12 +422,15 @@
 
         @VisibleForTesting
         protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
-            StatusBarMobileView view = onCreateStatusBarMobileView(slot);
+            // Use the `subId` field as a key to query for the correct context
+            StatusBarMobileView view = onCreateStatusBarMobileView(state.subId, slot);
             view.applyMobileState(state);
             mGroup.addView(view, index, onCreateLayoutParams());
 
             if (mIsInDemoMode) {
-                mDemoStatusIcons.addMobileView(state);
+                Context mobileContext = mMobileContextProvider
+                        .getMobileContextForSub(state.subId, mContext);
+                mDemoStatusIcons.addMobileView(state, mobileContext);
             }
             return view;
         }
@@ -423,8 +449,10 @@
                     mContext, slot, mWifiViewModelProvider.get());
         }
 
-        private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
-            StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot);
+        private StatusBarMobileView onCreateStatusBarMobileView(int subId, String slot) {
+            Context mobileContext = mMobileContextProvider.getMobileContextForSub(subId, mContext);
+            StatusBarMobileView view = StatusBarMobileView
+                    .fromContext(mobileContext, slot);
             return view;
         }
 
@@ -512,7 +540,9 @@
             }
 
             if (mIsInDemoMode) {
-                mDemoStatusIcons.updateMobileState(state);
+                Context mobileContext = mMobileContextProvider
+                        .getMobileContextForSub(state.subId, mContext);
+                mDemoStatusIcons.updateMobileState(state, mobileContext);
             }
         }
 
@@ -549,7 +579,7 @@
         }
 
         protected DemoStatusIcons createDemoStatusIcons() {
-            return new DemoStatusIcons((LinearLayout) mGroup, mIconSize, mFeatureFlags);
+            return new DemoStatusIcons((LinearLayout) mGroup, mIconSize);
         }
     }
 }
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 e9771d2..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);
@@ -589,7 +587,7 @@
     public void reset(boolean hideBouncerWhenShowing) {
         if (mShowing) {
             // Hide quick settings.
-            mNotificationPanelViewController.resetViews(/* animate= */ true);
+            mNotificationPanelViewController.resetViews(/* animate= */ !mOccluded);
             // Hide bouncer and quick-quick settings.
             if (mOccluded && !mDozing) {
                 mCentralSurfaces.hideKeyguard();
@@ -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/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index b1104ae..a1e0c50 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -33,8 +33,6 @@
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.Dependency;
-import com.android.systemui.ForegroundServiceNotificationListener;
 import com.android.systemui.InitController;
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
@@ -183,10 +181,6 @@
             mLockscreenUserManager.setUpWithPresenter(this);
             mGutsManager.setUpWithPresenter(
                     this, mNotifListContainer, mOnSettingsClickListener);
-            // ForegroundServiceNotificationListener adds its listener in its constructor
-            // but we need to request it here in order for it to be instantiated.
-            // TODO: figure out how to do this correctly once Dependency.get() is gone.
-            Dependency.get(ForegroundServiceNotificationListener.class);
 
             onUserSwitched(mLockscreenUserManager.getCurrentUserId());
         });
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 5fd72b7..891f657 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -53,10 +53,10 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.DisableFlagsLogger.DisableState;
 import com.android.systemui.statusbar.OperatorNameView;
 import com.android.systemui.statusbar.OperatorNameViewController;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger.DisableState;
 import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
index 9ae378f..28ed080 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLogger.kt
@@ -19,7 +19,7 @@
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogLevel
 import com.android.systemui.log.dagger.CollapsedSbFragmentLog
-import com.android.systemui.statusbar.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
 import javax.inject.Inject
 
 /** Used by [CollapsedStatusBarFragment] to log messages to a [LogBuffer]. */
@@ -60,4 +60,4 @@
     }
 }
 
-private const val TAG = "CollapsedSbFragment"
\ No newline at end of file
+private const val TAG = "CollapsedSbFragment"
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/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index 7765427..103f3fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -46,7 +46,7 @@
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.flow.stateIn
 
 /**
  * Provides data related to the wifi state.
@@ -118,12 +118,19 @@
             }
         }
 
-        trySend(WIFI_NETWORK_DEFAULT)
         connectivityManager.registerNetworkCallback(WIFI_NETWORK_CALLBACK_REQUEST, callback)
 
         awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
     }
-        .shareIn(scope, started = SharingStarted.WhileSubscribed())
+        // There will be multiple wifi icons in different places that will frequently
+        // subscribe/unsubscribe to flows as the views attach/detach. Using [stateIn] ensures that
+        // new subscribes will get the latest value immediately upon subscription. Otherwise, the
+        // views could show stale data. See b/244173280.
+        .stateIn(
+            scope,
+            started = SharingStarted.WhileSubscribed(),
+            initialValue = WIFI_NETWORK_DEFAULT
+        )
 
     override val wifiActivity: Flow<WifiActivityModel> =
             if (wifiManager == null) {
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/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index 169347a..16306081 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -49,6 +49,7 @@
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.UserAvatarView;
+import com.android.systemui.user.data.source.UserRecord;
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
@@ -79,7 +80,7 @@
     @VisibleForTesting
     UserAvatarView mUserAvatarView;
     private View mUserAvatarViewWithBackground;
-    UserSwitcherController.UserRecord mCurrentUser;
+    UserRecord mCurrentUser;
     private boolean mIsKeyguardShowing;
 
     // State info for the user switch and keyguard
@@ -269,10 +270,10 @@
      * @return true if the current user has changed
      */
     private boolean updateCurrentUser() {
-        UserSwitcherController.UserRecord previousUser = mCurrentUser;
+        UserRecord previousUser = mCurrentUser;
         mCurrentUser = null;
         for (int i = 0; i < mAdapter.getCount(); i++) {
-            UserSwitcherController.UserRecord r = mAdapter.getItem(i);
+            UserRecord r = mAdapter.getItem(i);
             if (r.isCurrent) {
                 mCurrentUser = r;
                 return !mCurrentUser.equals(previousUser);
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/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 03ab888..e2f5734 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
+import com.android.systemui.user.data.source.UserRecord;
 import com.android.systemui.util.ViewController;
 
 import java.util.ArrayList;
@@ -287,8 +288,8 @@
                 }
                 KeyguardUserDetailItemView newView = (KeyguardUserDetailItemView)
                         mAdapter.getView(i, oldView, mListView);
-                UserSwitcherController.UserRecord userTag =
-                        (UserSwitcherController.UserRecord) newView.getTag();
+                UserRecord userTag =
+                        (UserRecord) newView.getTag();
                 if (userTag.isCurrent) {
                     if (i != 0) {
                         Log.w(TAG, "Current user is not the first view in the list");
@@ -443,7 +444,7 @@
         private KeyguardUserSwitcherController mKeyguardUserSwitcherController;
         private View mCurrentUserView;
         // List of users where the first entry is always the current user
-        private ArrayList<UserSwitcherController.UserRecord> mUsersOrdered = new ArrayList<>();
+        private ArrayList<UserRecord> mUsersOrdered = new ArrayList<>();
 
         KeyguardUserAdapter(Context context, Resources resources, LayoutInflater layoutInflater,
                 UserSwitcherController controller,
@@ -464,10 +465,10 @@
         }
 
         void refreshUserOrder() {
-            ArrayList<UserSwitcherController.UserRecord> users = super.getUsers();
+            ArrayList<UserRecord> users = super.getUsers();
             mUsersOrdered = new ArrayList<>(users.size());
             for (int i = 0; i < users.size(); i++) {
-                UserSwitcherController.UserRecord record = users.get(i);
+                UserRecord record = users.get(i);
                 if (record.isCurrent) {
                     mUsersOrdered.add(0, record);
                 } else {
@@ -477,19 +478,19 @@
         }
 
         @Override
-        protected ArrayList<UserSwitcherController.UserRecord> getUsers() {
+        protected ArrayList<UserRecord> getUsers() {
             return mUsersOrdered;
         }
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
-            UserSwitcherController.UserRecord item = getItem(position);
+            UserRecord item = getItem(position);
             return createUserDetailItemView(convertView, parent, item);
         }
 
         KeyguardUserDetailItemView convertOrInflate(View convertView, ViewGroup parent) {
             if (!(convertView instanceof KeyguardUserDetailItemView)
-                    || !(convertView.getTag() instanceof UserSwitcherController.UserRecord)) {
+                    || !(convertView.getTag() instanceof UserRecord)) {
                 convertView = mLayoutInflater.inflate(
                         R.layout.keyguard_user_switcher_item, parent, false);
             }
@@ -497,7 +498,7 @@
         }
 
         KeyguardUserDetailItemView createUserDetailItemView(View convertView, ViewGroup parent,
-                UserSwitcherController.UserRecord item) {
+                UserRecord item) {
             KeyguardUserDetailItemView v = convertOrInflate(convertView, parent);
             v.setOnClickListener(this);
 
@@ -513,7 +514,7 @@
                 v.bind(name, drawable, item.info.id);
             }
             v.setActivated(item.isCurrent);
-            v.setDisabledByAdmin(item.isDisabledByAdmin);
+            v.setDisabledByAdmin(mController.isDisabledByAdmin(item));
             v.setEnabled(item.isSwitchToEnabled);
             v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA);
 
@@ -524,7 +525,7 @@
             return v;
         }
 
-        private Drawable getDrawable(UserSwitcherController.UserRecord item) {
+        private Drawable getDrawable(UserRecord item) {
             Drawable drawable;
             if (item.isCurrent && item.isGuest) {
                 drawable = mContext.getDrawable(R.drawable.ic_avatar_guest_user);
@@ -547,7 +548,7 @@
 
         @Override
         public void onClick(View v) {
-            UserSwitcherController.UserRecord user = (UserSwitcherController.UserRecord) v.getTag();
+            UserRecord user = (UserRecord) v.getTag();
 
             if (mKeyguardUserSwitcherController.isListAnimating()) {
                 return;
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 836d571..3b8ed33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -45,6 +45,7 @@
 import android.provider.Settings;
 import android.telephony.TelephonyCallback;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -54,6 +55,7 @@
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
+import androidx.collection.SimpleArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
@@ -83,6 +85,8 @@
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 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;
 
@@ -97,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;
@@ -138,6 +148,9 @@
     private final InteractionJankMonitor mInteractionJankMonitor;
     private final LatencyTracker mLatencyTracker;
     private final DialogLaunchAnimator mDialogLaunchAnimator;
+    private final SimpleArrayMap<UserRecord, EnforcedAdmin> mEnforcedAdminByUserRecord =
+            new SimpleArrayMap<>();
+    private final ArraySet<UserRecord> mDisabledByAdmin = new ArraySet<>();
 
     private ArrayList<UserRecord> mUsers = new ArrayList<>();
     @VisibleForTesting
@@ -149,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;
@@ -252,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);
@@ -317,7 +334,6 @@
         }
         mForcePictureLoadForUserId.clear();
 
-        final boolean addUsersWhenLocked = mAddUsersFromLockScreen;
         mBgExecutor.execute(() ->  {
             List<UserInfo> infos = mUserManager.getAliveUsers();
             if (infos == null) {
@@ -428,7 +444,7 @@
     }
 
     boolean anyoneCanCreateUsers() {
-        return systemCanCreateUsers() && mAddUsersFromLockScreen;
+        return systemCanCreateUsers() && mAddUsersFromLockScreen.getValue();
     }
 
     boolean canCreateGuest(boolean hasExistingGuest) {
@@ -444,7 +460,7 @@
     }
 
     boolean createIsRestricted() {
-        return !mAddUsersFromLockScreen;
+        return !mAddUsersFromLockScreen.getValue();
     }
 
     boolean canCreateSupervisedUser() {
@@ -510,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) {
@@ -598,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();
         }
@@ -614,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)
@@ -766,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.
      *
@@ -776,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();
@@ -833,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
@@ -946,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;
@@ -975,6 +1041,21 @@
         return mKeyguardStateController;
     }
 
+    /**
+     * Returns the {@link EnforcedAdmin} for the given record, or {@code null} if there isn't one.
+     */
+    @Nullable
+    public EnforcedAdmin getEnforcedAdmin(UserRecord record) {
+        return mEnforcedAdminByUserRecord.get(record);
+    }
+
+    /**
+     * Returns {@code true} if the given record is disabled by the admin; {@code false} otherwise.
+     */
+    public boolean isDisabledByAdmin(UserRecord record) {
+        return mDisabledByAdmin.contains(record);
+    }
+
     public static abstract class BaseUserAdapter extends BaseAdapter {
 
         final UserSwitcherController mController;
@@ -1041,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() {
@@ -1082,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);
         }
 
@@ -1106,11 +1151,11 @@
                 UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId());
         if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
                 UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) {
-            record.isDisabledByAdmin = true;
-            record.enforcedAdmin = admin;
+            mDisabledByAdmin.add(record);
+            mEnforcedAdminByUserRecord.put(record, admin);
         } else {
-            record.isDisabledByAdmin = false;
-            record.enforcedAdmin = null;
+            mDisabledByAdmin.remove(record);
+            mEnforcedAdminByUserRecord.put(record, null);
         }
     }
 
@@ -1152,74 +1197,6 @@
         }
     }
 
-    public static final class UserRecord {
-        public final UserInfo info;
-        public final Bitmap picture;
-        public final boolean isGuest;
-        public final boolean isCurrent;
-        public final boolean isAddUser;
-        public final boolean isAddSupervisedUser;
-        /** If true, the record is only visible to the owner and only when unlocked. */
-        public final boolean isRestricted;
-        public boolean isDisabledByAdmin;
-        public EnforcedAdmin enforcedAdmin;
-        public boolean isSwitchToEnabled;
-
-        public UserRecord(UserInfo info, Bitmap picture, boolean isGuest, boolean isCurrent,
-                boolean isAddUser, boolean isRestricted, boolean isSwitchToEnabled,
-                boolean isAddSupervisedUser) {
-            this.info = info;
-            this.picture = picture;
-            this.isGuest = isGuest;
-            this.isCurrent = isCurrent;
-            this.isAddUser = isAddUser;
-            this.isRestricted = isRestricted;
-            this.isSwitchToEnabled = isSwitchToEnabled;
-            this.isAddSupervisedUser = isAddSupervisedUser;
-        }
-
-        public UserRecord copyWithIsCurrent(boolean _isCurrent) {
-            return new UserRecord(info, picture, isGuest, _isCurrent, isAddUser, isRestricted,
-                    isSwitchToEnabled, isAddSupervisedUser);
-        }
-
-        public int resolveId() {
-            if (isGuest || info == null) {
-                return UserHandle.USER_NULL;
-            }
-            return info.id;
-        }
-
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("UserRecord(");
-            if (info != null) {
-                sb.append("name=\"").append(info.name).append("\" id=").append(info.id);
-            } else {
-                if (isGuest) {
-                    sb.append("<add guest placeholder>");
-                } else if (isAddUser) {
-                    sb.append("<add user placeholder>");
-                }
-            }
-            if (isGuest) sb.append(" <isGuest>");
-            if (isAddUser) sb.append(" <isAddUser>");
-            if (isAddSupervisedUser) sb.append(" <isAddSupervisedUser>");
-            if (isCurrent) sb.append(" <isCurrent>");
-            if (picture != null) sb.append(" <hasPicture>");
-            if (isRestricted) sb.append(" <isRestricted>");
-            if (isDisabledByAdmin) {
-                sb.append(" <isDisabledByAdmin>");
-                sb.append(" enforcedAdmin=").append(enforcedAdmin);
-            }
-            if (isSwitchToEnabled) {
-                sb.append(" <isSwitchToEnabled>");
-            }
-            sb.append(')');
-            return sb.toString();
-        }
-    }
-
     private final KeyguardStateController.Callback mCallback =
             new KeyguardStateController.Callback() {
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 3a0ac1b..734eeec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
 
 import android.annotation.LayoutRes
 import android.annotation.SuppressLint
@@ -37,30 +37,30 @@
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
 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.
+ * A generic controller that can temporarily display a new view in a new window.
  *
- * Subclasses need to override and implement [updateChipView], which is where they can control what
+ * 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 chip in a certain state, since they receive <T> in [updateChipView].
+ * display the view in a certain state, since they receive <T> in [updateView].
+ *
+ * TODO(b/245610654): Remove all the media-specific logic from this class.
  */
-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,
+abstract class TemporaryViewDisplayController<T : TemporaryViewInfo>(
+    internal val context: Context,
+    internal val logger: MediaTttLogger,
+    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,
 ) {
     /**
      * Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -85,31 +85,31 @@
      */
     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 view currently being displayed. Null if the view is not being displayed. */
+    private var view: ViewGroup? = null
 
-    /** The chip info currently being displayed. Null if the chip is not being displayed. */
-    internal var chipInfo: T? = 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 chip. */
-    private var cancelChipViewTimeout: Runnable? = null
+    /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
+    private var cancelViewTimeout: Runnable? = null
 
     /**
-     * Displays the chip with the provided [newChipInfo].
+     * Displays the view with the provided [newInfo].
      *
-     * This method handles inflating and attaching the view, then delegates to [updateChipView] to
-     * display the correct information in the chip.
+     * This method handles inflating and attaching the view, then delegates to [updateView] to
+     * display the correct information in the view.
      */
-    fun displayChip(newChipInfo: T) {
-        val currentChipView = chipView
+    fun displayView(newInfo: T) {
+        val currentView = view
 
-        if (currentChipView != null) {
-            updateChipView(newChipInfo, currentChipView)
+        if (currentView != null) {
+            updateView(newInfo, currentView)
         } else {
-            // The chip is new, so set up all our callbacks and inflate the view
+            // 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 chip. (Per b/239426653, we want
-            // the chip to show over the dream state, so we should only wake up if the screen is
+            // 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(
@@ -119,79 +119,79 @@
                 )
             }
 
-            inflateAndUpdateChip(newChipInfo)
+            inflateAndUpdateView(newInfo)
         }
 
-        // Cancel and re-set the chip timeout each time we get a new state.
+        // Cancel and re-set the view 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
+            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
        )
-        cancelChipViewTimeout?.run()
-        cancelChipViewTimeout = mainExecutor.executeDelayed(
-            { removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
+        cancelViewTimeout?.run()
+        cancelViewTimeout = mainExecutor.executeDelayed(
+            { removeView(TemporaryDisplayRemovalReason.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
+    /** 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(chipLayoutRes, null) as ViewGroup
-        chipView = newChipView
-        updateChipView(newChipInfo, newChipView)
-        windowManager.addView(newChipView, windowLayoutParams)
-        animateChipIn(newChipView)
+                .inflate(viewLayoutRes, null) as ViewGroup
+        view = newView
+        updateView(newInfo, newView)
+        windowManager.addView(newView, windowLayoutParams)
+        animateViewIn(newView)
     }
 
-    /** Removes then re-inflates the chip. */
-    private fun reinflateChip() {
-        val currentChipInfo = chipInfo
-        if (chipView == null || currentChipInfo == null) { return }
+    /** Removes then re-inflates the view. */
+    private fun reinflateView() {
+        val currentInfo = info
+        if (view == null || currentInfo == null) { return }
 
-        windowManager.removeView(chipView)
-        inflateAndUpdateChip(currentChipInfo)
+        windowManager.removeView(view)
+        inflateAndUpdateView(currentInfo)
     }
 
     private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
         override fun onDensityOrFontScaleChanged() {
-            reinflateChip()
+            reinflateView()
         }
     }
 
     /**
-     * Hides the chip.
+     * Hides the view.
      *
-     * @param removalReason a short string describing why the chip was removed (timeout, state
+     * @param removalReason a short string describing why the view was removed (timeout, state
      *     change, etc.)
      */
-    open fun removeChip(removalReason: String) {
-        if (chipView == null) { return }
+    open fun removeView(removalReason: String) {
+        if (view == 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()
+        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 [currentChipView] based on [newChipInfo].
+     * A method implemented by subclasses to update [currentView] based on [newInfo].
      */
     @CallSuper
-    open fun updateChipView(newChipInfo: T, currentChipView: ViewGroup) {
-        chipInfo = newChipInfo
+    open fun updateView(newInfo: T, currentView: ViewGroup) {
+        info = newInfo
     }
 
     /**
-     * A method that can be implemented by subclcasses to do custom animations for when the chip
+     * A method that can be implemented by subclasses to do custom animations for when the view
      * appears.
      */
-    open fun animateChipIn(chipView: ViewGroup) {}
+    open fun animateViewIn(view: ViewGroup) {}
 
     /**
      * Returns the size that the icon should be, or null if no size override is needed.
@@ -209,12 +209,12 @@
      * @return the content description of the icon.
      */
     internal fun setIcon(
-        currentChipView: ViewGroup,
+        currentView: ViewGroup,
         appPackageName: String?,
         appIconDrawableOverride: Drawable? = null,
         appNameOverride: CharSequence? = null,
     ): CharSequence {
-        val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
+        val appIconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
         val iconInfo = getIconInfo(appPackageName)
 
         getIconSize(iconInfo.isAppIcon)?.let { size ->
@@ -264,9 +264,9 @@
 // Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
 // UpdateMediaTapToTransferReceiverDisplayTest
 private const val WINDOW_TITLE = "Media Transfer Chip View"
-private val TAG = MediaTttChipControllerCommon::class.simpleName!!
+private val TAG = TemporaryViewDisplayController::class.simpleName!!
 
-object MediaTttRemovalReason {
+object TemporaryDisplayRemovalReason {
     const val REASON_TIMEOUT = "TIMEOUT"
     const val REASON_SCREEN_TAP = "SCREEN_TAP"
 }
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/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index abffe555..27746c0 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -56,13 +56,11 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
 import com.android.systemui.statusbar.phone.DozeServiceHost;
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -152,10 +150,6 @@
     abstract DockManager bindDockManager(DockManagerImpl dockManager);
 
     @Binds
-    abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
-            KeyguardEnvironmentImpl keyguardEnvironment);
-
-    @Binds
     abstract ShadeController provideShadeController(ShadeControllerImpl shadeController);
 
     @SysUISingleton
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 80c55c0..8a51cd6 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
@@ -37,6 +38,7 @@
 import android.widget.TextView
 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 +46,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
@@ -51,7 +55,10 @@
 import com.android.systemui.statusbar.policy.UserSwitcherController.BaseUserAdapter
 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.statusbar.policy.UserSwitcherController.UserRecord
+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
 
@@ -63,11 +70,12 @@
 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
@@ -81,130 +89,43 @@
         }
     }
     // When the add users options become available, insert another option to manage users
-    private val manageUserRecord = UserRecord(
-        null /* info */,
-        null /* picture */,
-        false /* isGuest */,
-        false /* isCurrent */,
-        false /* isAddUser */,
-        false /* isRestricted */,
-        false /* isSwitchToEnabled */,
-        false /* isAddSupervisedUser */
-    )
+    private val manageUserRecord =
+        UserRecord(
+            null /* info */,
+            null /* picture */,
+            false /* isGuest */,
+            false /* isCurrent */,
+            false /* isAddUser */,
+            false /* isRestricted */,
+            false /* isSwitchToEnabled */,
+            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)
 
         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)
 
@@ -345,11 +266,18 @@
     }
 
     override fun onBackPressed() {
+        if (isUsingModernArchitecture()) {
+            return super.onBackPressed()
+        }
+
         finish()
     }
 
     override fun onDestroy() {
         super.onDestroy()
+        if (isUsingModernArchitecture()) {
+            return
+        }
 
         broadcastDispatcher.unregisterReceiver(broadcastReceiver)
         userTracker.removeCallback(userSwitchedCallback)
@@ -375,6 +303,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,
@@ -397,4 +329,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/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
similarity index 74%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
index 88e227b..18ae107 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepositoryModule.kt
@@ -12,12 +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.log.dagger
+package com.android.systemui.user.data.repository
 
-import javax.inject.Qualifier
+import dagger.Binds
+import dagger.Module
 
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+@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
new file mode 100644
index 0000000..cf6da9a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.source
+
+import android.content.pm.UserInfo
+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. */
+data class UserRecord(
+    /** Relevant user information. If `null`, this record is not a user but an option item. */
+    @JvmField val info: UserInfo? = null,
+    /** An image representing the user. */
+    @JvmField val picture: Bitmap? = null,
+    /** Whether this record represents an option to switch to a guest user. */
+    @JvmField val isGuest: Boolean = false,
+    /** Whether this record represents the currently-selected user. */
+    @JvmField val isCurrent: Boolean = false,
+    /** Whether this record represents an option to add another user to the device. */
+    @JvmField val isAddUser: Boolean = false,
+    /**
+     * 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)
+    }
+
+    /**
+     * Returns the user ID for the user represented by this instance or [UserHandle.USER_NULL] if
+     * this instance if a guest or does not represent a user (represents an option item).
+     */
+    fun resolveId(): Int {
+        return if (isGuest || info == null) {
+            UserHandle.USER_NULL
+        } else {
+            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/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
similarity index 75%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
index 88e227b..823bf74 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserActionModel.kt
@@ -12,12 +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.log.dagger
+package com.android.systemui.user.shared.model
 
-import javax.inject.Qualifier
-
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+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..66ce01b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -0,0 +1,199 @@
+/*
+ * 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.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 = 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
new file mode 100644
index 0000000..f71d596
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -0,0 +1,154 @@
+/*
+ * 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 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.flow
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+
+/**
+ * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
+ * Note that the new Flow will not start emitting until it has received two emissions from the
+ * upstream Flow.
+ *
+ * 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> = flow {
+    val noVal = Any()
+    var previousValue: Any? = noVal
+    collect { newVal ->
+        if (previousValue != noVal) {
+            @Suppress("UNCHECKED_CAST")
+            emit(transform(previousValue as T, newVal))
+        }
+        previousValue = newVal
+    }
+}
+
+/**
+ * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
+ * [initialValue] will be used as the "old" value for the first emission.
+ *
+ * Useful for code that needs to compare the current value to the previous value.
+ */
+fun <T, R> Flow<T>.pairwiseBy(
+    initialValue: T,
+    transform: suspend (previousValue: T, newValue: T) -> R,
+): Flow<R> =
+    onStart { emit(initialValue) }.pairwiseBy(transform)
+
+/**
+ * Returns a new [Flow] that produces the two most recent emissions from [this]. Note that the new
+ * Flow will not start emitting until it has received two emissions from the upstream Flow.
+ *
+ * Useful for code that needs to compare the current value to the previous value.
+ */
+fun <T> Flow<T>.pairwise(): Flow<WithPrev<T>> = pairwiseBy(::WithPrev)
+
+/**
+ * Returns a new [Flow] that produces the two most recent emissions from [this]. [initialValue]
+ * will be used as the "old" value for the first emission.
+ *
+ * Useful for code that needs to compare the current value to the previous value.
+ */
+fun <T> Flow<T>.pairwise(initialValue: T): Flow<WithPrev<T>> = pairwiseBy(initialValue, ::WithPrev)
+
+/** Holds a [newValue] emitted from a [Flow], along with the [previousValue] emitted value. */
+data class WithPrev<T>(val previousValue: T, val newValue: T)
+
+/**
+ * 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,
+    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
+        // If an element is present in the new set, but on the old one, then it was added
+        val added = new - old
+        transform(removed, added)
+    }
+
+/**
+ * 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>(
+    /** Elements that are present in the first [Set] but not in the second. */
+    val removed: Set<T>,
+    /** 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/util/leak/GarbageMonitor.java b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
index e910f72..619e50b 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/GarbageMonitor.java
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
@@ -58,7 +59,6 @@
 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.QSIconViewImpl;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.MessageRouter;
@@ -304,7 +304,7 @@
         MemoryIconDrawable(Context context) {
             baseIcon = context.getDrawable(R.drawable.ic_memory).mutate();
             dp = context.getResources().getDisplayMetrics().density;
-            paint.setColor(QSIconViewImpl.getIconColorForState(context, STATE_ACTIVE));
+            paint.setColor(Color.WHITE);
         }
 
         public void setRss(long rss) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/OWNERS b/packages/SystemUI/src/com/android/systemui/volume/OWNERS
new file mode 100644
index 0000000..e627d61
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/OWNERS
@@ -0,0 +1,4 @@
[email protected] # send reviews here
+
[email protected]
[email protected]
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 13c3df3..c7ba518 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -48,7 +48,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
@@ -248,6 +247,7 @@
 
     private final ConfigurationController mConfigurationController;
     private final MediaOutputDialogFactory mMediaOutputDialogFactory;
+    private final VolumePanelFactory mVolumePanelFactory;
     private final ActivityStarter mActivityStarter;
 
     private boolean mShowing;
@@ -279,6 +279,7 @@
             DeviceProvisionedController deviceProvisionedController,
             ConfigurationController configurationController,
             MediaOutputDialogFactory mediaOutputDialogFactory,
+            VolumePanelFactory volumePanelFactory,
             ActivityStarter activityStarter,
             InteractionJankMonitor interactionJankMonitor) {
         mContext =
@@ -290,6 +291,7 @@
         mDeviceProvisionedController = deviceProvisionedController;
         mConfigurationController = configurationController;
         mMediaOutputDialogFactory = mediaOutputDialogFactory;
+        mVolumePanelFactory = volumePanelFactory;
         mActivityStarter = activityStarter;
         mShowActiveStreamOnly = showActiveStreamOnly();
         mHasSeenODICaptionsTooltip =
@@ -1045,10 +1047,9 @@
         if (mSettingsIcon != null) {
             mSettingsIcon.setOnClickListener(v -> {
                 Events.writeEvent(Events.EVENT_SETTINGS_CLICK);
-                Intent intent = new Intent(Settings.Panel.ACTION_VOLUME);
                 dismissH(DISMISS_REASON_SETTINGS_CLICKED);
                 mMediaOutputDialogFactory.dismiss();
-                mActivityStarter.startActivity(intent, true /* dismissShade */);
+                mVolumePanelFactory.create(true /* aboveStatusBar */, null);
             });
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
new file mode 100644
index 0000000..87a167b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialog.java
@@ -0,0 +1,305 @@
+/*
+ * 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.volume;
+
+import android.bluetooth.BluetoothDevice;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.provider.SettingsSlicesContract;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.lifecycle.LiveData;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceMetadata;
+import androidx.slice.widget.EventInfo;
+import androidx.slice.widget.SliceLiveData;
+
+import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+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;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Visual presentation of the volume panel dialog.
+ */
+public class VolumePanelDialog extends SystemUIDialog implements LifecycleOwner {
+    private static final String TAG = "VolumePanelDialog";
+
+    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;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Map<Uri, LiveData<Slice>> mSliceLiveData = new LinkedHashMap<>();
+    private final HashSet<Uri> mLoadedSlices = new HashSet<>();
+    private boolean mSlicesReadyToLoad;
+    private LocalBluetoothProfileManager mProfileManager;
+
+    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);
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.d(TAG, "onCreate");
+
+        View dialogView = LayoutInflater.from(getContext()).inflate(R.layout.volume_panel_dialog,
+                null);
+        final Window window = getWindow();
+        window.setContentView(dialogView);
+
+        Button doneButton = dialogView.findViewById(R.id.done_button);
+        doneButton.setOnClickListener(v -> dismiss());
+        Button settingsButton = dialogView.findViewById(R.id.settings_button);
+        settingsButton.setOnClickListener(v -> {
+            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(
+                getContext(), null);
+        if (localBluetoothManager != null) {
+            mProfileManager = localBluetoothManager.getProfileManager();
+        }
+
+        mVolumePanelSlices = dialogView.findViewById(R.id.volume_panel_parent_layout);
+        mVolumePanelSlices.setLayoutManager(new LinearLayoutManager(getContext()));
+
+        loadAllSlices();
+
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
+    }
+
+    private void loadAllSlices() {
+        mSliceLiveData.clear();
+        mLoadedSlices.clear();
+        final List<Uri> sliceUris = getSlices();
+
+        for (Uri uri : sliceUris) {
+            final LiveData<Slice> sliceLiveData = SliceLiveData.fromUri(getContext(), uri,
+                    (int type, Throwable source) -> {
+                        if (!removeSliceLiveData(uri)) {
+                            mLoadedSlices.add(uri);
+                        }
+                    });
+
+            // Add slice first to make it in order.  Will remove it later if there's an error.
+            mSliceLiveData.put(uri, sliceLiveData);
+
+            sliceLiveData.observe(this, slice -> {
+                if (mLoadedSlices.contains(uri)) {
+                    return;
+                }
+                Log.d(TAG, "received slice: " + (slice == null ? null : slice.getUri()));
+                final SliceMetadata metadata = SliceMetadata.from(getContext(), slice);
+                if (slice == null || metadata.isErrorSlice()) {
+                    if (!removeSliceLiveData(uri)) {
+                        mLoadedSlices.add(uri);
+                    }
+                } else if (metadata.getLoadingState() == SliceMetadata.LOADED_ALL) {
+                    mLoadedSlices.add(uri);
+                } else {
+                    mHandler.postDelayed(() -> {
+                        mLoadedSlices.add(uri);
+                        setupAdapterWhenReady();
+                    }, DURATION_SLICE_BINDING_TIMEOUT_MS);
+                }
+
+                setupAdapterWhenReady();
+            });
+        }
+    }
+
+    private void setupAdapterWhenReady() {
+        if (mLoadedSlices.size() == mSliceLiveData.size() && !mSlicesReadyToLoad) {
+            mSlicesReadyToLoad = true;
+            mVolumePanelSlicesAdapter = new VolumePanelSlicesAdapter(this, mSliceLiveData);
+            mVolumePanelSlicesAdapter.setOnSliceActionListener((eventInfo, sliceItem) -> {
+                if (eventInfo.actionType == EventInfo.ACTION_TYPE_SLIDER) {
+                    return;
+                }
+                this.dismiss();
+            });
+            if (mSliceLiveData.size() < DEFAULT_SLICE_SIZE) {
+                mVolumePanelSlices.setMinimumHeight(0);
+            }
+            mVolumePanelSlices.setAdapter(mVolumePanelSlicesAdapter);
+        }
+    }
+
+    private boolean removeSliceLiveData(Uri uri) {
+        boolean removed = false;
+        // Keeps observe media output slice
+        if (!uri.equals(MEDIA_OUTPUT_INDICATOR_SLICE_URI)) {
+            Log.d(TAG, "remove uri: " + uri);
+            removed = mSliceLiveData.remove(uri) != null;
+            if (mVolumePanelSlicesAdapter != null) {
+                mVolumePanelSlicesAdapter.updateDataSet(new ArrayList<>(mSliceLiveData.values()));
+            }
+        }
+        return removed;
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        Log.d(TAG, "onStart");
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        Log.d(TAG, "onStop");
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+    }
+
+    private List<Uri> getSlices() {
+        final List<Uri> uris = new ArrayList<>();
+        uris.add(REMOTE_MEDIA_SLICE_URI);
+        uris.add(VOLUME_MEDIA_URI);
+        Uri controlUri = getExtraControlUri();
+        if (controlUri != null) {
+            Log.d(TAG, "add extra control slice");
+            uris.add(controlUri);
+        }
+        uris.add(MEDIA_OUTPUT_INDICATOR_SLICE_URI);
+        uris.add(VOLUME_CALL_URI);
+        uris.add(VOLUME_RINGER_URI);
+        uris.add(VOLUME_ALARM_URI);
+        return uris;
+    }
+
+    private static final String SETTINGS_SLICE_AUTHORITY = "com.android.settings.slices";
+    private static final Uri REMOTE_MEDIA_SLICE_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SETTINGS_SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+            .appendPath(MediaOutputConstants.KEY_REMOTE_MEDIA)
+            .build();
+    private static final Uri VOLUME_MEDIA_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SETTINGS_SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+            .appendPath("media_volume")
+            .build();
+    private static final Uri MEDIA_OUTPUT_INDICATOR_SLICE_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SETTINGS_SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT)
+            .appendPath("media_output_indicator")
+            .build();
+    private static final Uri VOLUME_CALL_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SETTINGS_SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+            .appendPath("call_volume")
+            .build();
+    private static final Uri VOLUME_RINGER_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SETTINGS_SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+            .appendPath("ring_volume")
+            .build();
+    private static final Uri VOLUME_ALARM_URI = new Uri.Builder()
+            .scheme(ContentResolver.SCHEME_CONTENT)
+            .authority(SETTINGS_SLICE_AUTHORITY)
+            .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
+            .appendPath("alarm_volume")
+            .build();
+
+    private Uri getExtraControlUri() {
+        Uri controlUri = null;
+        final BluetoothDevice bluetoothDevice = findActiveDevice();
+        if (bluetoothDevice != null) {
+            // The control slice width = dialog width - horizontal padding of two sides
+            final int dialogWidth =
+                    getWindow().getWindowManager().getCurrentWindowMetrics().getBounds().width();
+            final int controlSliceWidth = dialogWidth
+                    - getContext().getResources().getDimensionPixelSize(
+                    R.dimen.volume_panel_slice_horizontal_padding) * 2;
+            final String uri = BluetoothUtils.getControlUriMetaData(bluetoothDevice);
+            if (!TextUtils.isEmpty(uri)) {
+                try {
+                    controlUri = Uri.parse(uri + controlSliceWidth);
+                } catch (NullPointerException exception) {
+                    Log.d(TAG, "unable to parse extra control uri");
+                    controlUri = null;
+                }
+            }
+        }
+        return controlUri;
+    }
+
+    private BluetoothDevice findActiveDevice() {
+        if (mProfileManager != null) {
+            final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
+            if (a2dpProfile != null) {
+                return a2dpProfile.getActiveDevice();
+            }
+        }
+        return null;
+    }
+
+    @NonNull
+    @Override
+    public Lifecycle getLifecycle() {
+        return mLifecycleRegistry;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt
new file mode 100644
index 0000000..f11d5d1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelDialogReceiver.kt
@@ -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.systemui.volume
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.Log
+import javax.inject.Inject
+
+private const val TAG = "VolumePanelDialogReceiver"
+private const val LAUNCH_ACTION = "com.android.systemui.action.LAUNCH_VOLUME_PANEL_DIALOG"
+private const val DISMISS_ACTION = "com.android.systemui.action.DISMISS_VOLUME_PANEL_DIALOG"
+
+/**
+ * BroadcastReceiver for handling volume panel dialog intent
+ */
+class VolumePanelDialogReceiver @Inject constructor(
+    private val volumePanelFactory: VolumePanelFactory
+) : BroadcastReceiver() {
+    override fun onReceive(context: Context, intent: Intent) {
+        Log.d(TAG, "onReceive intent" + intent.action)
+        if (TextUtils.equals(LAUNCH_ACTION, intent.action) ||
+                TextUtils.equals(Settings.Panel.ACTION_VOLUME, intent.action)) {
+            volumePanelFactory.create(true, null)
+        } else if (TextUtils.equals(DISMISS_ACTION, intent.action)) {
+            volumePanelFactory.dismiss()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
new file mode 100644
index 0000000..0debe0e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelFactory.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.volume
+
+import android.content.Context
+import android.util.Log
+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"
+private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+
+/**
+ * Factory to create [VolumePanelDialog] objects. This is the dialog that allows the user to adjust
+ * multiple streams with sliders.
+ */
+@SysUISingleton
+class VolumePanelFactory @Inject constructor(
+    private val context: Context,
+    private val activityStarter: ActivityStarter,
+    private val dialogLaunchAnimator: DialogLaunchAnimator
+) {
+    companion object {
+        var volumePanelDialog: VolumePanelDialog? = null
+    }
+
+    /** Creates a [VolumePanelDialog]. The dialog will be animated from [view] if it is not null. */
+    fun create(aboveStatusBar: Boolean, view: View? = null) {
+        if (volumePanelDialog?.isShowing == true) {
+            return
+        }
+
+        val dialog = VolumePanelDialog(context, activityStarter, aboveStatusBar)
+        volumePanelDialog = dialog
+
+        // Show the dialog.
+        if (view != null) {
+            dialogLaunchAnimator.showFromView(dialog, view, animateBackgroundBoundsChange = true)
+        } else {
+            dialog.show()
+        }
+    }
+
+    /** Dismiss [VolumePanelDialog] if exist. */
+    fun dismiss() {
+        if (DEBUG) {
+            Log.d(TAG, "dismiss dialog")
+        }
+        volumePanelDialog?.dismiss()
+        volumePanelDialog = null
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelSlicesAdapter.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelSlicesAdapter.java
new file mode 100644
index 0000000..2371402
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelSlicesAdapter.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.systemui.volume;
+
+import static android.app.slice.Slice.HINT_ERROR;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+
+import android.content.Context;
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LiveData;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.widget.SliceView;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * RecyclerView adapter for Slices in Settings Panels.
+ */
+public class VolumePanelSlicesAdapter extends
+        RecyclerView.Adapter<VolumePanelSlicesAdapter.SliceRowViewHolder> {
+
+    private final List<LiveData<Slice>> mSliceLiveData;
+    private final LifecycleOwner mLifecycleOwner;
+    private SliceView.OnSliceActionListener mOnSliceActionListener;
+
+    public VolumePanelSlicesAdapter(LifecycleOwner lifecycleOwner,
+            Map<Uri, LiveData<Slice>> sliceLiveData) {
+        mLifecycleOwner = lifecycleOwner;
+        mSliceLiveData = new ArrayList<>(sliceLiveData.values());
+    }
+
+    @NonNull
+    @Override
+    public SliceRowViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
+        final Context context = viewGroup.getContext();
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        View view = inflater.inflate(R.layout.volume_panel_slice_slider_row, viewGroup, false);
+        return new SliceRowViewHolder(view);
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull SliceRowViewHolder sliceRowViewHolder, int position) {
+        sliceRowViewHolder.onBind(mSliceLiveData.get(position), position);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSliceLiveData.size();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return position;
+    }
+
+    void setOnSliceActionListener(SliceView.OnSliceActionListener listener) {
+        mOnSliceActionListener = listener;
+    }
+
+    void updateDataSet(ArrayList<LiveData<Slice>> list) {
+        mSliceLiveData.clear();
+        mSliceLiveData.addAll(list);
+        notifyDataSetChanged();
+    }
+
+    /**
+     * ViewHolder for binding Slices to SliceViews.
+     */
+    public class SliceRowViewHolder extends RecyclerView.ViewHolder {
+
+        private final SliceView mSliceView;
+
+        public SliceRowViewHolder(View view) {
+            super(view);
+            mSliceView = view.findViewById(R.id.slice_view);
+            mSliceView.setMode(SliceView.MODE_LARGE);
+            mSliceView.setShowTitleItems(true);
+            mSliceView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+            mSliceView.setOnSliceActionListener(mOnSliceActionListener);
+        }
+
+        /**
+         * Called when the view is displayed.
+         */
+        public void onBind(LiveData<Slice> sliceLiveData, int position) {
+            sliceLiveData.observe(mLifecycleOwner, mSliceView);
+
+            // Do not show the divider above media devices switcher slice per request
+            final Slice slice = sliceLiveData.getValue();
+
+            // Hides slice which reports with error hint or not contain any slice sub-item.
+            if (slice == null || !isValidSlice(slice)) {
+                mSliceView.setVisibility(View.GONE);
+            } else {
+                mSliceView.setVisibility(View.VISIBLE);
+            }
+        }
+
+        private boolean isValidSlice(Slice slice) {
+            if (slice.getHints().contains(HINT_ERROR)) {
+                return false;
+            }
+            for (SliceItem item : slice.getItems()) {
+                if (item.getFormat().equals(FORMAT_SLICE)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index f3855bd..c5792b9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -30,6 +30,7 @@
 import com.android.systemui.volume.VolumeComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
 import com.android.systemui.volume.VolumeDialogImpl;
+import com.android.systemui.volume.VolumePanelFactory;
 
 import dagger.Binds;
 import dagger.Module;
@@ -52,6 +53,7 @@
             DeviceProvisionedController deviceProvisionedController,
             ConfigurationController configurationController,
             MediaOutputDialogFactory mediaOutputDialogFactory,
+            VolumePanelFactory volumePanelFactory,
             ActivityStarter activityStarter,
             InteractionJankMonitor interactionJankMonitor) {
         VolumeDialogImpl impl = new VolumeDialogImpl(
@@ -61,6 +63,7 @@
                 deviceProvisionedController,
                 configurationController,
                 mediaOutputDialogFactory,
+                volumePanelFactory,
                 activityStarter,
                 interactionJankMonitor);
         impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
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
+
[email protected]
[email protected]
[email protected]
[email protected]
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 199048e..4e77514 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -57,12 +57,9 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.notification.NotificationChannelHelper;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -103,7 +100,6 @@
     private final NotificationVisibilityProvider mVisibilityProvider;
     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
     private final NotificationLockscreenUserManager mNotifUserManager;
-    private final NotificationGroupManagerLegacy mNotificationGroupManager;
     private final CommonNotifCollection mCommonNotifCollection;
     private final NotifPipeline mNotifPipeline;
     private final Executor mSysuiMainExecutor;
@@ -130,7 +126,6 @@
             NotificationInterruptStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
-            NotificationGroupManagerLegacy groupManager,
             CommonNotifCollection notifCollection,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
@@ -148,7 +143,6 @@
                     interruptionStateProvider,
                     zenModeController,
                     notifUserManager,
-                    groupManager,
                     notifCollection,
                     notifPipeline,
                     sysUiState,
@@ -171,7 +165,6 @@
             NotificationInterruptStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
-            NotificationGroupManagerLegacy groupManager,
             CommonNotifCollection notifCollection,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
@@ -185,7 +178,6 @@
         mVisibilityProvider = visibilityProvider;
         mNotificationInterruptStateProvider = interruptionStateProvider;
         mNotifUserManager = notifUserManager;
-        mNotificationGroupManager = groupManager;
         mCommonNotifCollection = notifCollection;
         mNotifPipeline = notifPipeline;
         mSysuiMainExecutor = sysuiMainExecutor;
@@ -319,28 +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 removeNotificationEntry(String key) {
-                sysuiMainExecutor.execute(() -> {
-                    final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
-                    if (entry != null) {
-                        mNotificationGroupManager.onEntryRemoved(entry);
-                    }
-                });
-            }
-
-            @Override
             public void updateNotificationBubbleButton(String key) {
                 sysuiMainExecutor.execute(() -> {
                     final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
@@ -351,16 +321,6 @@
             }
 
             @Override
-            public void updateNotificationSuppression(String key) {
-                sysuiMainExecutor.execute(() -> {
-                    final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
-                    if (entry != null) {
-                        mNotificationGroupManager.updateSuppression(entry);
-                    }
-                });
-            }
-
-            @Override
             public void onStackExpandChanged(boolean shouldExpand) {
                 sysuiMainExecutor.execute(() -> {
                     sysUiState.setFlag(QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED, shouldExpand)
@@ -486,11 +446,6 @@
         mBubbles.onNotificationChannelModified(pkg, user, channel, modificationType);
     }
 
-    /**
-     * Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
-     * Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
-     * Instead, this is taken care of by {@link BubbleCoordinator}.
-     */
     private DismissedByUserStats getDismissedByUserStats(
             NotificationEntry entry,
             boolean isVisible) {
@@ -532,7 +487,10 @@
                                     REASON_GROUP_SUMMARY_CANCELED);
                         }
                     } else {
-                        mNotificationGroupManager.onEntryRemoved(entry);
+                        for (NotifCallback cb : mCallbacks) {
+                            cb.removeNotification(entry, getDismissedByUserStats(entry, true),
+                                    REASON_GROUP_SUMMARY_CANCELED);
+                        }
                     }
                 }, mSysuiMainExecutor);
     }
@@ -676,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/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a4a59fc..3961a8b 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -34,7 +34,6 @@
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
 import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
 import android.view.KeyEvent;
 
 import androidx.annotation.NonNull;
@@ -62,12 +61,10 @@
 import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
 import com.android.wm.shell.onehanded.OneHandedUiEventLogger;
 import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.protolog.ShellProtoLogImpl;
 import com.android.wm.shell.splitscreen.SplitScreen;
 import com.android.wm.shell.sysui.ShellInterface;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.Executor;
@@ -336,44 +333,7 @@
         if (mShell.handleCommand(args, pw)) {
             return;
         }
-        // Handle logging commands if provided
-        if (handleLoggingCommand(args, pw)) {
-            return;
-        }
         // Dump WMShell stuff here if no commands were handled
         mShell.dump(pw);
     }
-
-    @Override
-    public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
-        PrintWriter pw = new PrintWriter(new ParcelFileDescriptor.AutoCloseOutputStream(outFd));
-        handleLoggingCommand(args, pw);
-        pw.flush();
-        pw.close();
-    }
-
-    private boolean handleLoggingCommand(String[] args, PrintWriter pw) {
-        ShellProtoLogImpl protoLogImpl = ShellProtoLogImpl.getSingleInstance();
-        for (int i = 0; i < args.length; i++) {
-            switch (args[i]) {
-                case "enable-text": {
-                    String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
-                    int result = protoLogImpl.startTextLogging(groups, pw);
-                    if (result == 0) {
-                        pw.println("Starting logging on groups: " + Arrays.toString(groups));
-                    }
-                    return true;
-                }
-                case "disable-text": {
-                    String[] groups = Arrays.copyOfRange(args, i + 1, args.length);
-                    int result = protoLogImpl.stopTextLogging(groups, pw);
-                    if (result == 0) {
-                        pw.println("Stopping logging on groups: " + Arrays.toString(groups));
-                    }
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 }
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index ba28045..0fa3d36 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -53,7 +53,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.REGISTER_WINDOW_MANAGER_LISTENERS" />
 
-    <application android:debuggable="true" android:largeHeap="true"
+    <application android:debuggable="true" android:largeHeap="true" android:testOnly="true"
             android:enableOnBackInvokedCallback="true" >
         <uses-library android:name="android.test.runner" />
 
diff --git a/packages/SystemUI/tests/AndroidTest.xml b/packages/SystemUI/tests/AndroidTest.xml
index 5ffd300..31e7bd2 100644
--- a/packages/SystemUI/tests/AndroidTest.xml
+++ b/packages/SystemUI/tests/AndroidTest.xml
@@ -16,6 +16,7 @@
 <configuration description="Runs Tests for SystemUI.">
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
         <option name="test-file-name" value="SystemUITests.apk" />
+        <option name="install-arg" value="-t" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
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/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 0ac4eda..914d945 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -259,6 +259,7 @@
 
     @Test
     fun unregisterListeners_validate() {
+        clockEventController.clock = clock
         clockEventController.unregisterListeners()
         verify(broadcastDispatcher).unregisterReceiver(any())
         verify(configurationController).removeCallback(any())
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/FaceAuthReasonTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/FaceAuthReasonTest.kt
new file mode 100644
index 0000000..68d0f41
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/FaceAuthReasonTest.kt
@@ -0,0 +1,41 @@
+/*
+ * 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 androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import junit.framework.Assert
+import kotlin.reflect.full.declaredMembers
+import org.junit.Test
+
+@SmallTest
+class FaceAuthReasonTest : SysuiTestCase() {
+    @Test
+    fun testApiReasonToUiEvent_forAllReasons_isNotNull() {
+        val declaredMemberProperties = FaceAuthApiRequestReason.Companion::class.declaredMembers
+
+        declaredMemberProperties.forEach {
+            val reason = it.call()
+            try {
+                apiRequestReasonToUiEvent(reason as String)
+            } catch (e: Exception) {
+                Assert.fail(
+                    "Expected the reason: \"$reason\" to have a corresponding FaceAuthUiEvent"
+                )
+            }
+        }
+    }
+}
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 bb455da..0bf038d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -86,6 +86,7 @@
     becauseCannotSkipBouncer = false,
     biometricSettingEnabledForUser = false,
     bouncerFullyShown = false,
+    bouncerIsOrWillShow = false,
     onlyFaceEnrolled = false,
     faceAuthenticated = false,
     faceDisabled = 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/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index aecec9d..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);
@@ -387,6 +389,33 @@
     }
 
     @Test
+    public void onResume_sideFpsHintShouldBeShown_sideFpsHintShown() {
+        setupGetSecurityView();
+        setupConditionsToEnableSideFpsHint();
+        mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE);
+        reset(mSidefpsController);
+
+        mKeyguardSecurityContainerController.onResume(0);
+
+        verify(mSidefpsController).show();
+        verify(mSidefpsController, never()).hide();
+    }
+
+    @Test
+    public void onResume_sideFpsHintShouldNotBeShown_sideFpsHintHidden() {
+        setupGetSecurityView();
+        setupConditionsToEnableSideFpsHint();
+        setSideFpsHintEnabledFromResources(false);
+        mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE);
+        reset(mSidefpsController);
+
+        mKeyguardSecurityContainerController.onResume(0);
+
+        verify(mSidefpsController).hide();
+        verify(mSidefpsController, never()).show();
+    }
+
+    @Test
     public void showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() {
         // GIVEN the current security method is SimPin
         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index f2ac0c7..28e99da 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -57,7 +57,7 @@
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.UserSwitcherController.UserRecord;
+import com.android.systemui.user.data.source.UserRecord;
 import com.android.systemui.util.settings.GlobalSettings;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 3e00aec..093e592 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -16,7 +16,9 @@
 
 package com.android.keyguard;
 
+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.telephony.SubscriptionManager.DATA_ROAMING_DISABLE;
 import static android.telephony.SubscriptionManager.NAME_SOURCE_CARRIER_ID;
@@ -30,6 +32,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;
@@ -72,6 +75,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;
@@ -86,6 +90,8 @@
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.jank.InteractionJankMonitor;
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.UiEventLogger;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.ILockSettings;
@@ -96,6 +102,7 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -190,6 +197,12 @@
     private KeyguardUpdateMonitorLogger mKeyguardUpdateMonitorLogger;
     @Mock
     private IActivityManager mActivityService;
+    @Mock
+    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);
@@ -212,6 +225,7 @@
     private MockitoSession mMockitoSession;
     private StatusBarStateController.StateListener mStatusBarStateListener;
     private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;
+    private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
 
     @Before
     public void setup() throws RemoteException {
@@ -225,6 +239,7 @@
         when(mFaceManager.hasEnrolledTemplates()).thenReturn(true);
         when(mFaceManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
         when(mFaceManager.getSensorPropertiesInternal()).thenReturn(mFaceSensorProperties);
+        when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
 
         // [email protected] does not support detection, only authentication.
         when(mFaceSensorProperties.isEmpty()).thenReturn(false);
@@ -656,7 +671,8 @@
         // Stop scanning when bouncer becomes visible
         setKeyguardBouncerVisibility(true);
         clearInvocations(mFaceManager);
-        mKeyguardUpdateMonitor.requestFaceAuth(true);
+        mKeyguardUpdateMonitor.requestFaceAuth(true,
+                FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
         verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                 anyBoolean());
     }
@@ -1500,10 +1516,13 @@
         keyguardIsVisible();
 
         mTestableLooper.processAllMessages();
+        clearInvocations(mUiEventLogger);
 
         assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
 
-        mKeyguardUpdateMonitor.requestFaceAuth(true);
+        mKeyguardUpdateMonitor.requestFaceAuth(true,
+                FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
+
         verify(mFaceManager).authenticate(any(),
                 mCancellationSignalCaptor.capture(),
                 mAuthenticationCallbackCaptor.capture(),
@@ -1512,7 +1531,7 @@
                 anyBoolean());
         CancellationSignal cancelSignal = mCancellationSignalCaptor.getValue();
 
-        bouncerFullyVisible();
+        bouncerWillBeVisibleSoon();
         mTestableLooper.processAllMessages();
 
         assertThat(cancelSignal.isCanceled()).isTrue();
@@ -1546,6 +1565,28 @@
         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 faceAuthEnabled() {
         // this ensures KeyguardUpdateMonitor updates the cached mIsFaceEnrolled flag using the
         // face manager mock wire-up in setup()
@@ -1594,8 +1635,13 @@
                 .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT, "Fingerprint locked out");
     }
 
+    private void fingerprintAcquireStart() {
+        mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
+                .onAuthenticationAcquired(FINGERPRINT_ACQUIRED_START);
+    }
+
     private void triggerSuccessfulFaceAuth() {
-        mKeyguardUpdateMonitor.requestFaceAuth(true);
+        mKeyguardUpdateMonitor.requestFaceAuth(true, FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
         verify(mFaceManager).authenticate(any(),
                 any(),
                 mAuthenticationCallbackCaptor.capture(),
@@ -1670,6 +1716,11 @@
         setKeyguardBouncerVisibility(true);
     }
 
+    private void bouncerWillBeVisibleSoon() {
+        mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true, false);
+        mTestableLooper.processAllMessages();
+    }
+
     private void setKeyguardBouncerVisibility(boolean isVisible) {
         mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible, isVisible);
         mTestableLooper.processAllMessages();
@@ -1710,7 +1761,8 @@
                     mStatusBarStateController, mLockPatternUtils,
                     mAuthController, mTelephonyListenerManager,
                     mInteractionJankMonitor, mLatencyTracker, mActiveUnlockConfig,
-                    mKeyguardUpdateMonitorLogger);
+                    mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
+                    mPowerManager);
             setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
new file mode 100644
index 0000000..6b1ef38
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/ChooserSelectorTest.kt
@@ -0,0 +1,179 @@
+package com.android.systemui
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flag
+import com.android.systemui.flags.FlagListenable
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.UnreleasedFlag
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.test.TestCoroutineDispatcher
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ChooserSelectorTest : SysuiTestCase() {
+
+    private val flagListener = kotlinArgumentCaptor<FlagListenable.Listener>()
+
+    private val testDispatcher = TestCoroutineDispatcher()
+    private val testScope = CoroutineScope(testDispatcher)
+
+    private lateinit var chooserSelector: ChooserSelector
+
+    @Mock private lateinit var mockContext: Context
+    @Mock private lateinit var mockPackageManager: PackageManager
+    @Mock private lateinit var mockResources: Resources
+    @Mock private lateinit var mockFeatureFlags: FeatureFlags
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        `when`(mockContext.packageManager).thenReturn(mockPackageManager)
+        `when`(mockContext.resources).thenReturn(mockResources)
+        `when`(mockResources.getString(anyInt())).thenReturn(
+                ComponentName("TestPackage", "TestClass").flattenToString())
+
+        chooserSelector = ChooserSelector(mockContext, mockFeatureFlags, testScope, testDispatcher)
+    }
+
+    @After
+    fun tearDown() {
+        testDispatcher.cleanupTestCoroutines()
+    }
+
+    @Test
+    fun initialize_registersFlagListenerUntilScopeCancelled() {
+        // Arrange
+
+        // Act
+        chooserSelector.start()
+
+        // Assert
+        verify(mockFeatureFlags).addListener(
+                eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture())
+        verify(mockFeatureFlags, never()).removeListener(any())
+
+        // Act
+        testScope.cancel()
+
+        // Assert
+        verify(mockFeatureFlags).removeListener(eq(flagListener.value))
+    }
+
+    @Test
+    fun initialize_enablesUnbundledChooser_whenFlagEnabled() {
+        // Arrange
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
+
+        // Act
+        chooserSelector.start()
+
+        // Assert
+        verify(mockPackageManager).setComponentEnabledSetting(
+                eq(ComponentName("TestPackage", "TestClass")),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
+                anyInt())
+    }
+
+    @Test
+    fun initialize_disablesUnbundledChooser_whenFlagDisabled() {
+        // Arrange
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
+
+        // Act
+        chooserSelector.start()
+
+        // Assert
+        verify(mockPackageManager).setComponentEnabledSetting(
+                eq(ComponentName("TestPackage", "TestClass")),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
+                anyInt())
+    }
+
+    @Test
+    fun enablesUnbundledChooser_whenFlagBecomesEnabled() {
+        // Arrange
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
+        chooserSelector.start()
+        verify(mockFeatureFlags).addListener(
+                eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture())
+        verify(mockPackageManager, never()).setComponentEnabledSetting(
+                any(), eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED), anyInt())
+
+        // Act
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
+        flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id))
+
+        // Assert
+        verify(mockPackageManager).setComponentEnabledSetting(
+                eq(ComponentName("TestPackage", "TestClass")),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_ENABLED),
+                anyInt())
+    }
+
+    @Test
+    fun disablesUnbundledChooser_whenFlagBecomesDisabled() {
+        // Arrange
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(true)
+        chooserSelector.start()
+        verify(mockFeatureFlags).addListener(
+                eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture())
+        verify(mockPackageManager, never()).setComponentEnabledSetting(
+                any(), eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED), anyInt())
+
+        // Act
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
+        flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id))
+
+        // Assert
+        verify(mockPackageManager).setComponentEnabledSetting(
+                eq(ComponentName("TestPackage", "TestClass")),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_DISABLED),
+                anyInt())
+    }
+
+    @Test
+    fun doesNothing_whenAnotherFlagChanges() {
+        // Arrange
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
+        chooserSelector.start()
+        verify(mockFeatureFlags).addListener(
+                eq<Flag<*>>(Flags.CHOOSER_UNBUNDLED), flagListener.capture())
+        clearInvocations(mockPackageManager)
+
+        // Act
+        `when`(mockFeatureFlags.isEnabled(any<UnreleasedFlag>())).thenReturn(false)
+        flagListener.value.onFlagChanged(TestFlagEvent(Flags.CHOOSER_UNBUNDLED.id + 1))
+
+        // Assert
+        verifyZeroInteractions(mockPackageManager)
+    }
+
+    private class TestFlagEvent(override val flagId: Int) : FlagListenable.FlagEvent {
+        override fun requestNoRestart() {}
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index ba21afd..b47b08c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -44,12 +44,10 @@
 
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.systemui.appops.AppOpsController;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.util.time.FakeSystemClock;
+import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -64,9 +62,7 @@
 public class ForegroundServiceControllerTest extends SysuiTestCase {
     private ForegroundServiceController mFsc;
     private ForegroundServiceNotificationListener mListener;
-    private NotificationEntryListener mEntryListener;
-    private final FakeSystemClock mClock = new FakeSystemClock();
-    @Mock private NotificationEntryManager mEntryManager;
+    private NotifCollectionListener mCollectionListener;
     @Mock private AppOpsController mAppOpsController;
     @Mock private Handler mMainHandler;
     @Mock private NotifPipeline mNotifPipeline;
@@ -79,12 +75,13 @@
         MockitoAnnotations.initMocks(this);
         mFsc = new ForegroundServiceController(mAppOpsController, mMainHandler);
         mListener = new ForegroundServiceNotificationListener(
-                mContext, mFsc, mEntryManager, mNotifPipeline, mClock);
-        ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
-                ArgumentCaptor.forClass(NotificationEntryListener.class);
-        verify(mEntryManager).addNotificationEntryListener(
+                mContext, mFsc, mNotifPipeline);
+        mListener.init();
+        ArgumentCaptor<NotifCollectionListener> entryListenerCaptor =
+                ArgumentCaptor.forClass(NotifCollectionListener.class);
+        verify(mNotifPipeline).addCollectionListener(
                 entryListenerCaptor.capture());
-        mEntryListener = entryListenerCaptor.getValue();
+        mCollectionListener = entryListenerCaptor.getValue();
     }
 
     @Test
@@ -449,7 +446,7 @@
 
     private NotificationEntry addFgEntry() {
         NotificationEntry entry = createFgEntry();
-        mEntryListener.onPendingEntryAdded(entry);
+        mCollectionListener.onEntryAdded(entry);
         return entry;
     }
 
@@ -461,12 +458,10 @@
     }
 
     private void entryRemoved(StatusBarNotification notification) {
-        mEntryListener.onEntryRemoved(
+        mCollectionListener.onEntryRemoved(
                 new NotificationEntryBuilder()
                         .setSbn(notification)
                         .build(),
-                null,
-                false,
                 REASON_APP_CANCEL);
     }
 
@@ -475,7 +470,7 @@
                 .setSbn(notification)
                 .setImportance(importance)
                 .build();
-        mEntryListener.onPendingEntryAdded(entry);
+        mCollectionListener.onEntryAdded(entry);
     }
 
     private void entryUpdated(StatusBarNotification notification, int importance) {
@@ -483,7 +478,7 @@
                 .setSbn(notification)
                 .setImportance(importance)
                 .build();
-        mEntryListener.onPreEntryUpdated(entry);
+        mCollectionListener.onEntryUpdated(entry);
     }
 
     @UserIdInt private static final int USERID_ONE = 10; // UserManagerService.MIN_USER_ID;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 64a7986..df10dfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -16,7 +16,6 @@
 
 import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
 import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
-import static android.view.DisplayCutout.BOUNDS_POSITION_LENGTH;
 import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
 import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -36,6 +35,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -49,7 +49,6 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
-import android.graphics.Insets;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -60,7 +59,6 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
-import android.util.RotationUtils;
 import android.util.Size;
 import android.view.Display;
 import android.view.DisplayCutout;
@@ -80,6 +78,8 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.decor.CornerDecorProvider;
+import com.android.systemui.decor.CutoutDecorProviderFactory;
+import com.android.systemui.decor.CutoutDecorProviderImpl;
 import com.android.systemui.decor.DecorProvider;
 import com.android.systemui.decor.DecorProviderFactory;
 import com.android.systemui.decor.FaceScanningOverlayProviderImpl;
@@ -157,6 +157,9 @@
     @Mock
     private DisplayInfo mDisplayInfo;
     private PrivacyDotViewController.ShowingListener mPrivacyDotShowingListener;
+    @Mock
+    private CutoutDecorProviderFactory mCutoutFactory;
+    private List<DecorProvider> mMockCutoutList;
 
     @Before
     public void setup() {
@@ -206,6 +209,11 @@
                 DisplayCutout.BOUNDS_POSITION_RIGHT,
                 R.layout.privacy_dot_bottom_right));
 
+        // Default no cutout
+        mMockCutoutList = new ArrayList<>();
+        doAnswer(it -> !(mMockCutoutList.isEmpty())).when(mCutoutFactory).getHasProviders();
+        doReturn(mMockCutoutList).when(mCutoutFactory).getProviders();
+
         mFaceScanningDecorProvider = spy(new FaceScanningOverlayProviderImpl(
                 BOUNDS_POSITION_TOP,
                 mAuthController,
@@ -239,6 +247,11 @@
                 super.updateOverlayWindowVisibilityIfViewExists(view);
                 mExecutor.runAllReady();
             }
+
+            @Override
+            protected CutoutDecorProviderFactory getCutoutFactory() {
+                return ScreenDecorationsTest.this.mCutoutFactory;
+            }
         });
         mScreenDecorations.mDisplayInfo = mDisplayInfo;
         doReturn(1f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
@@ -429,11 +442,9 @@
     public void testNoRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
         // No views added.
@@ -448,11 +459,9 @@
     public void testNoRounding_NoCutout_PrivacyDot_NoFaceScanning() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
 
@@ -484,11 +493,9 @@
     public void testRounding_NoCutout_NoPrivacyDot_NoFaceScanning() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
 
@@ -516,11 +523,9 @@
     public void testRounding_NoCutout_PrivacyDot_NoFaceScanning() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
 
@@ -555,10 +560,9 @@
                 /* roundedTopDrawable */,
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
                 /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
+
+        // no cutout (default)
 
         mScreenDecorations.start();
         // Size of corner view should same as rounded_corner_radius{_top|_bottom}
@@ -574,11 +578,9 @@
                 /* roundedTopDrawable */,
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded3px)
                 /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
         View leftRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP].getRootView()
@@ -611,13 +613,10 @@
                 /* roundedTopDrawable */,
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
                 /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.start();
         View topRoundedCorner = mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].getRootView()
@@ -647,13 +646,10 @@
     public void testNoRounding_CutoutShortEdge_NoPrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Top window is created for top cutout.
@@ -671,13 +667,10 @@
     public void testNoRounding_CutoutShortEdge_PrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Top window is created for top cutout.
@@ -706,13 +699,10 @@
     public void testNoRounding_CutoutLongEdge_NoPrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.start();
         // Left window is created for left cutout.
@@ -734,13 +724,10 @@
     public void testNoRounding_CutoutLongEdge_PrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.start();
         // Left window is created for left cutout.
@@ -762,13 +749,10 @@
     public void testRounding_CutoutShortEdge_NoPrivacyDot() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Top window is created for rounded corner and top cutout.
@@ -791,13 +775,10 @@
     public void testRounding_CutoutShortEdge_PrivacyDot() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Top window is created for rounded corner and top cutout.
@@ -823,13 +804,10 @@
     public void testRounding_CutoutLongEdge_NoPrivacyDot() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.start();
         // Left window is created for rounded corner and left cutout.
@@ -842,13 +820,10 @@
     public void testRounding_CutoutLongEdge_PrivacyDot() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.start();
         // Left window is created for rounded corner, left cutout, and privacy.
@@ -863,13 +838,11 @@
     public void testRounding_CutoutShortAndLongEdge_NoPrivacyDot() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // top and left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Top window is created for rounded corner and top cutout.
@@ -883,13 +856,11 @@
     public void testRounding_CutoutShortAndLongEdge_PrivacyDot() {
         setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                20 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                20 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // top and left cutout
-        final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Top window is created for rounded corner and top cutout.
@@ -905,21 +876,16 @@
     public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_NoPrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // Set to short edge cutout(top).
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         verifyOverlaysExistAndAdded(false, true, false, false, View.VISIBLE);
 
         // Switch to long edge cutout(left).
-        final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.onConfigurationChanged(new Configuration());
         verifyOverlaysExistAndAdded(true, false, false, false, View.VISIBLE);
@@ -929,13 +895,10 @@
     public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout_PrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         // Set to short edge cutout(top).
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         verifyOverlaysExistAndAdded(false, true, false, true, View.VISIBLE);
@@ -943,9 +906,7 @@
         verify(mDotViewController, times(1)).setShowingListener(null);
 
         // Switch to long edge cutout(left).
-        final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.set(0, new CutoutDecorProviderImpl(BOUNDS_POSITION_LEFT));
 
         mScreenDecorations.onConfigurationChanged(new Configuration());
         verifyOverlaysExistAndAdded(true, false, true, false, View.VISIBLE);
@@ -973,20 +934,16 @@
     public void testDelayedCutout_NoPrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
-        // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        // No cutout (default)
 
         mScreenDecorations.start();
         verifyOverlaysExistAndAdded(false, false, false, false, null);
 
-        when(mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
-                .thenReturn(true);
+        // top cutout
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+
         mScreenDecorations.onConfigurationChanged(new Configuration());
 
         // Only top windows should be added.
@@ -997,13 +954,9 @@
     public void testDelayedCutout_PrivacyDot() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
-        // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
         // Both top and bottom windows should be added with INVISIBLE because of only privacy dot,
@@ -1015,9 +968,9 @@
         verify(mDotViewController, times(1)).setShowingListener(
                 mScreenDecorations.mPrivacyDotShowingListener);
 
-        when(mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
-                .thenReturn(true);
+        // top cutout
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+
         mScreenDecorations.onConfigurationChanged(new Configuration());
 
         // Both top and bottom windows should be added with VISIBLE because of privacy dot and
@@ -1043,8 +996,7 @@
                 /* roundedTopDrawable */,
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
                 /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning*/);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
         mDisplayInfo.rotation = Surface.ROTATION_0;
 
         mScreenDecorations.start();
@@ -1058,8 +1010,7 @@
                 /* roundedTopDrawable */,
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
                 /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning*/);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
         mDisplayInfo.rotation = Surface.ROTATION_270;
 
         mScreenDecorations.onConfigurationChanged(null);
@@ -1072,8 +1023,7 @@
     public void testOnlyRoundedCornerRadiusTop() {
         setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         mScreenDecorations.start();
 
@@ -1094,8 +1044,7 @@
     public void testOnlyRoundedCornerRadiusBottom() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         mScreenDecorations.start();
 
@@ -1166,13 +1115,10 @@
     public void testSupportHwcLayer_SwitchFrom_NotSupport() {
         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // should only inflate mOverlays when the hwc doesn't support screen decoration
@@ -1195,16 +1141,13 @@
     public void testNotSupportHwcLayer_SwitchFrom_Support() {
         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
         decorationSupport.format = PixelFormat.R_8;
         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // should only inflate hwc layer when the hwc supports screen decoration
@@ -1234,16 +1177,13 @@
                 /* roundedTopDrawable */,
                 getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
                 /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                true /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
         decorationSupport.format = PixelFormat.R_8;
         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
         // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
@@ -1277,11 +1217,9 @@
     public void testAutoShowHideOverlayWindowWhenNoRoundedAndNoCutout() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, true /* privacyDot */,
-                true /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
 
-        // no cutout
-        doReturn(null).when(mScreenDecorations).getCutout();
+        // no cutout (default)
 
         mScreenDecorations.start();
         // Inflate top and bottom overlay with INVISIBLE because of only privacy dots on sw layer
@@ -1315,16 +1253,13 @@
     public void testHwcLayer_noPrivacyDot_noFaceScanning() {
         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
         decorationSupport.format = PixelFormat.R_8;
         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
 
@@ -1337,16 +1272,13 @@
     public void testHwcLayer_PrivacyDot_FaceScanning() {
         setupResources(0 /* radius */, 10 /* radiusTop */, 20 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                true /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, true /* faceScanning */);
         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
         decorationSupport.format = PixelFormat.R_8;
         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
 
@@ -1364,16 +1296,13 @@
     public void testOnDisplayChanged_hwcLayer() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
         final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
         decorationSupport.format = PixelFormat.R_8;
         doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
 
@@ -1390,18 +1319,16 @@
     public void testOnDisplayChanged_nonHwcLayer() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         // top cutout
-        final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
-        doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
-                .when(mScreenDecorations).getCutout();
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
 
         mScreenDecorations.start();
 
-        final ScreenDecorations.DisplayCutoutView cutoutView =
-                mScreenDecorations.mCutoutViews[BOUNDS_POSITION_TOP];
+        final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView)
+                mScreenDecorations.getOverlayView(R.id.display_cutout);
+        assertNotNull(cutoutView);
         spyOn(cutoutView);
         doReturn(mDisplay).when(cutoutView).getDisplay();
 
@@ -1414,8 +1341,7 @@
     public void testHasSameProvidersWithNullOverlays() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, false /* fillCutout */, false /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
 
         mScreenDecorations.start();
 
@@ -1433,8 +1359,7 @@
     public void testHasSameProvidersWithPrivacyDots() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
-                0 /* roundedPadding */, true /* fillCutout */, true /* privacyDot */,
-                false /* faceScanning */);
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning */);
 
         mScreenDecorations.start();
 
@@ -1471,7 +1396,7 @@
 
     private void setupResources(int radius, int radiusTop, int radiusBottom,
             @Nullable Drawable roundedTopDrawable, @Nullable Drawable roundedBottomDrawable,
-            int roundedPadding, boolean fillCutout, boolean privacyDot, boolean faceScanning) {
+            int roundedPadding, boolean privacyDot, boolean faceScanning) {
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.array.config_displayUniqueIdArray,
                 new String[]{});
@@ -1511,8 +1436,6 @@
         }
         mContext.getOrCreateTestableResources().addOverride(
                 R.dimen.rounded_corner_content_padding, roundedPadding);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
 
         mPrivacyDecorProviders = new ArrayList<>();
         if (privacyDot) {
@@ -1531,19 +1454,4 @@
         when(mFaceScanningProviderFactory.getProviders()).thenReturn(mFaceScanningProviders);
         when(mFaceScanningProviderFactory.getHasProviders()).thenReturn(faceScanning);
     }
-
-    private DisplayCutout getDisplayCutoutForRotation(Insets safeInsets, Rect[] cutoutBounds) {
-        final int rotation = mContext.getDisplay().getRotation();
-        final Insets insets = RotationUtils.rotateInsets(safeInsets, rotation);
-        final Rect[] sorted = new Rect[BOUNDS_POSITION_LENGTH];
-        for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
-            final int rotatedPos = ScreenDecorations.getBoundPositionFromRotation(i, rotation);
-            if (cutoutBounds[i] != null) {
-                RotationUtils.rotateBounds(cutoutBounds[i], new Rect(0, 0, 100, 200), rotation);
-            }
-            sorted[rotatedPos] = cutoutBounds[i];
-        }
-        return new DisplayCutout(insets, sorted[BOUNDS_POSITION_LEFT], sorted[BOUNDS_POSITION_TOP],
-                sorted[BOUNDS_POSITION_RIGHT], sorted[BOUNDS_POSITION_BOTTOM]);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index e0d1f7a..c0acc71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -20,6 +20,8 @@
 import static android.hardware.biometrics.BiometricManager.Authenticators;
 import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FINGERPRINT_AND_FACE;
 
+import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static junit.framework.Assert.assertEquals;
@@ -75,6 +77,8 @@
 import android.testing.TestableContext;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
+import android.view.DisplayInfo;
+import android.view.Surface;
 import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
@@ -86,6 +90,7 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.Execution;
 import com.android.systemui.util.concurrency.FakeExecution;
@@ -157,13 +162,15 @@
     @Mock
     private InteractionJankMonitor mInteractionJankMonitor;
     @Captor
-    ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mFpAuthenticatorsRegisteredCaptor;
+    private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mFpAuthenticatorsRegisteredCaptor;
     @Captor
-    ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
+    private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> mFaceAuthenticatorsRegisteredCaptor;
     @Captor
-    ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
+    private ArgumentCaptor<BiometricStateListener> mBiometricStateCaptor;
     @Captor
-    ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
+    private ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor;
+    @Captor
+    private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefullnessObserverCaptor;
 
     private TestableContext mContextSpy;
     private Execution mExecution;
@@ -172,6 +179,9 @@
     private DelayableExecutor mBackgroundExecutor;
     private TestableAuthController mAuthController;
 
+    @Mock
+    private VibratorHelper mVibratorHelper;
+
     @Before
     public void setup() throws RemoteException {
         mContextSpy = spy(mContext);
@@ -230,10 +240,12 @@
                         true /* supportsSelfIllumination */,
                         true /* resetLockoutRequireHardwareAuthToken */));
         when(mFaceManager.getSensorPropertiesInternal()).thenReturn(faceProps);
+        when(mVibratorHelper.hasVibrator()).thenReturn(true);
 
         mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue,
                 mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager,
-                () -> mUdfpsController, () -> mSidefpsController, mStatusBarStateController);
+                () -> mUdfpsController, () -> mSidefpsController, mStatusBarStateController,
+                mVibratorHelper);
 
         mAuthController.start();
         verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -242,7 +254,9 @@
                 mFaceAuthenticatorsRegisteredCaptor.capture());
 
         when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
         verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture());
+        verify(mWakefulnessLifecycle).addObserver(mWakefullnessObserverCaptor.capture());
 
         mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(fpProps);
         mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
@@ -260,11 +274,13 @@
         reset(mFingerprintManager);
         reset(mFaceManager);
 
+        when(mVibratorHelper.hasVibrator()).thenReturn(true);
+
         // This test requires an uninitialized AuthController.
         AuthController authController = new TestableAuthController(mContextSpy, mExecution,
                 mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager,
                 mFaceManager, () -> mUdfpsController, () -> mSidefpsController,
-                mStatusBarStateController);
+                mStatusBarStateController, mVibratorHelper);
         authController.start();
 
         verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -290,11 +306,13 @@
         reset(mFingerprintManager);
         reset(mFaceManager);
 
+        when(mVibratorHelper.hasVibrator()).thenReturn(true);
+
         // This test requires an uninitialized AuthController.
         AuthController authController = new TestableAuthController(mContextSpy, mExecution,
                 mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager,
                 mFaceManager, () -> mUdfpsController, () -> mSidefpsController,
-                mStatusBarStateController);
+                mStatusBarStateController, mVibratorHelper);
         authController.start();
 
         verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(
@@ -720,13 +738,8 @@
     }
 
     @Test
-    public void testSubscribesToOrientationChangesWhenShowingDialog() {
-        showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
-
+    public void testSubscribesToOrientationChangesOnStart() {
         verify(mDisplayManager).registerDisplayListener(any(), eq(mHandler), anyLong());
-
-        mAuthController.hideAuthenticationDialog(REQUEST_ID);
-        verify(mDisplayManager).unregisterDisplayListener(any());
     }
 
     @Test
@@ -759,19 +772,148 @@
     }
 
     @Test
-    public void testForwardsDozeEvent() throws RemoteException {
+    public void testForwardsDozeEvents() throws RemoteException {
+        when(mStatusBarStateController.isDozing()).thenReturn(true);
+        when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
         mAuthController.setBiometicContextListener(mContextListener);
 
-        mStatusBarStateListenerCaptor.getValue().onDozingChanged(false);
         mStatusBarStateListenerCaptor.getValue().onDozingChanged(true);
+        mStatusBarStateListenerCaptor.getValue().onDozingChanged(false);
 
         InOrder order = inOrder(mContextListener);
-        // invoked twice since the initial state is false
-        order.verify(mContextListener, times(2)).onDozeChanged(eq(false));
-        order.verify(mContextListener).onDozeChanged(eq(true));
+        order.verify(mContextListener, times(2)).onDozeChanged(eq(true), eq(true));
+        order.verify(mContextListener).onDozeChanged(eq(false), eq(true));
+        order.verifyNoMoreInteractions();
     }
 
-    // Helpers
+    @Test
+    public void testForwardsWakeEvents() throws RemoteException {
+        when(mStatusBarStateController.isDozing()).thenReturn(false);
+        when(mWakefulnessLifecycle.getWakefulness()).thenReturn(WAKEFULNESS_AWAKE);
+        mAuthController.setBiometicContextListener(mContextListener);
+
+        mWakefullnessObserverCaptor.getValue().onStartedGoingToSleep();
+        mWakefullnessObserverCaptor.getValue().onFinishedGoingToSleep();
+        mWakefullnessObserverCaptor.getValue().onStartedWakingUp();
+        mWakefullnessObserverCaptor.getValue().onFinishedWakingUp();
+        mWakefullnessObserverCaptor.getValue().onPostFinishedWakingUp();
+
+        InOrder order = inOrder(mContextListener);
+        order.verify(mContextListener).onDozeChanged(eq(false), eq(true));
+        order.verify(mContextListener).onDozeChanged(eq(false), eq(false));
+        order.verify(mContextListener).onDozeChanged(eq(false), eq(true));
+        order.verifyNoMoreInteractions();
+    }
+
+    @Test
+    public void testGetFingerprintSensorLocationChanges_differentRotations() {
+        // GIVEN fp default location and mocked device dimensions
+        // Rotation 0, where "o" is the location of the FP sensor, if x or y = 0, it's the edge of
+        // the screen which is why a 1x1 width and height is represented by a 2x2 grid below:
+        //   [* o]
+        //   [* *]
+        Point fpDefaultLocation = new Point(1, 0);
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.logicalWidth = 1;
+        displayInfo.logicalHeight = 1;
+
+        // WHEN the rotation is 0, THEN no rotation applied
+        displayInfo.rotation = Surface.ROTATION_0;
+        assertEquals(
+                fpDefaultLocation,
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+
+        // WHEN the rotation is 270, THEN rotation is applied
+        //   [* *]
+        //   [* o]
+        displayInfo.rotation = Surface.ROTATION_270;
+        assertEquals(
+                new Point(1, 1),
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+
+        // WHEN the rotation is 180, THEN rotation is applied
+        //   [* *]
+        //   [o *]
+        displayInfo.rotation = Surface.ROTATION_180;
+        assertEquals(
+                new Point(0, 1),
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+
+        // WHEN the rotation is 90, THEN rotation is applied
+        //   [o *]
+        //   [* *]
+        displayInfo.rotation = Surface.ROTATION_90;
+        assertEquals(
+                new Point(0, 0),
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+    }
+
+    @Test
+    public void testGetFingerprintSensorLocationChanges_rotateRectangle() {
+        // GIVEN fp default location and mocked device dimensions
+        // Rotation 0, where "o" is the location of the FP sensor, if x or y = 0, it's the edge of
+        // the screen.
+        //   [* * o *]
+        //   [* * * *]
+        Point fpDefaultLocation = new Point(2, 0);
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.logicalWidth = 3;
+        displayInfo.logicalHeight = 1;
+
+        // WHEN the rotation is 0, THEN no rotation applied
+        displayInfo.rotation = Surface.ROTATION_0;
+        assertEquals(
+                fpDefaultLocation,
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+
+        // WHEN the rotation is 180, THEN rotation is applied
+        //   [* * * *]
+        //   [* o * *]
+        displayInfo.rotation = Surface.ROTATION_180;
+        assertEquals(
+                new Point(1, 1),
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+
+        // Rotation 270 & 90 have swapped logical width and heights
+        displayInfo.logicalWidth = 1;
+        displayInfo.logicalHeight = 3;
+
+        // WHEN the rotation is 270, THEN rotation is applied
+        //   [* *]
+        //   [* *]
+        //   [* o]
+        //   [* *]
+        displayInfo.rotation = Surface.ROTATION_270;
+        assertEquals(
+                new Point(1, 2),
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+
+        // WHEN the rotation is 90, THEN rotation is applied
+        //   [* *]
+        //   [o *]
+        //   [* *]
+        //   [* *]
+        displayInfo.rotation = Surface.ROTATION_90;
+        assertEquals(
+                new Point(0, 1),
+                mAuthController.rotateToCurrentOrientation(
+                        new Point(fpDefaultLocation), displayInfo)
+        );
+    }
 
     private void showDialog(int[] sensorIds, boolean credentialAllowed) {
         mAuthController.showAuthenticationDialog(createTestPromptInfo(),
@@ -831,12 +973,13 @@
                 FaceManager faceManager,
                 Provider<UdfpsController> udfpsControllerFactory,
                 Provider<SidefpsController> sidefpsControllerFactory,
-                StatusBarStateController statusBarStateController) {
+                StatusBarStateController statusBarStateController,
+                VibratorHelper vibratorHelper) {
             super(context, execution, commandQueue, activityTaskManager, windowManager,
                     fingerprintManager, faceManager, udfpsControllerFactory,
                     sidefpsControllerFactory, mDisplayManager, mWakefulnessLifecycle,
                     mUserManager, mLockPatternUtils, statusBarStateController,
-                    mInteractionJankMonitor, mHandler, mBackgroundExecutor);
+                    mInteractionJankMonitor, mHandler, mBackgroundExecutor, vibratorHelper);
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index d6afd6d..44ef922 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.biometrics
 
-import android.graphics.PointF
+import android.graphics.Point
 import android.hardware.biometrics.BiometricSourceType
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -31,11 +31,12 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.statusbar.phone.BiometricUnlockController
-import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.leak.RotationUtils
+import javax.inject.Provider
 import org.junit.After
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -45,15 +46,14 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.any
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 import org.mockito.MockitoSession
 import org.mockito.quality.Strictness
-import javax.inject.Provider
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -116,7 +116,7 @@
     @Test
     fun testFingerprintTrigger_KeyguardVisible_Ripple() {
         // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
-        val fpsLocation = PointF(5f, 5f)
+        val fpsLocation = Point(5, 5)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
@@ -139,7 +139,7 @@
     @Test
     fun testFingerprintTrigger_Dreaming_Ripple() {
         // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
-        val fpsLocation = PointF(5f, 5f)
+        val fpsLocation = Point(5, 5)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
@@ -162,7 +162,7 @@
     @Test
     fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
         // GIVEN fp exists & user doesn't need strong auth
-        val fpsLocation = PointF(5f, 5f)
+        val fpsLocation = Point(5, 5)
         `when`(authController.udfpsLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
@@ -184,7 +184,7 @@
     @Test
     fun testFingerprintTrigger_StrongAuthRequired_NoRipple() {
         // GIVEN fp exists & keyguard is visible
-        val fpsLocation = PointF(5f, 5f)
+        val fpsLocation = Point(5, 5)
         `when`(authController.udfpsLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
@@ -205,8 +205,8 @@
     @Test
     fun testFaceTriggerBypassEnabled_Ripple() {
         // GIVEN face auth sensor exists, keyguard is visible & strong auth isn't required
-        val faceLocation = PointF(5f, 5f)
-        `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation)
+        val faceLocation = Point(5, 5)
+        `when`(authController.faceSensorLocation).thenReturn(faceLocation)
         controller.onViewAttached()
 
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
@@ -229,8 +229,8 @@
     @Test
     fun testFaceTriggerNonBypass_NoRipple() {
         // GIVEN face auth sensor exists
-        val faceLocation = PointF(5f, 5f)
-        `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation)
+        val faceLocation = Point(5, 5)
+        `when`(authController.faceSensorLocation).thenReturn(faceLocation)
         controller.onViewAttached()
 
         // WHEN bypass isn't enabled & face authenticated
@@ -248,7 +248,7 @@
 
     @Test
     fun testNullFaceSensorLocationDoesNothing() {
-        `when`(authController.faceAuthSensorLocation).thenReturn(null)
+        `when`(authController.faceSensorLocation).thenReturn(null)
         controller.onViewAttached()
 
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
@@ -293,7 +293,7 @@
     @Test
     @RunWithLooper(setAsMainLooper = true)
     fun testAnimatorRunWhenWakeAndUnlock_fingerprint() {
-        val fpsLocation = PointF(5f, 5f)
+        val fpsLocation = Point(5, 5)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
@@ -311,8 +311,8 @@
     @Test
     @RunWithLooper(setAsMainLooper = true)
     fun testAnimatorRunWhenWakeAndUnlock_faceUdfpsFingerDown() {
-        val faceLocation = PointF(5f, 5f)
-        `when`(authController.faceAuthSensorLocation).thenReturn(faceLocation)
+        val faceLocation = Point(5, 5)
+        `when`(authController.faceSensorLocation).thenReturn(faceLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
new file mode 100644
index 0000000..419fedf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BiometricMessageDeferralTest : SysuiTestCase() {
+
+    @Test
+    fun testProcessNoMessages_noDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf())
+
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testProcessNonDeferredMessages_noDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+        // WHEN there are no deferred messages processed
+        for (i in 0..3) {
+            biometricMessageDeferral.processMessage(4, "test")
+        }
+
+        // THEN getDeferredMessage is null
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testAllProcessedMessagesWereDeferred() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+        // WHEN all the processed messages are a deferred message
+        for (i in 0..3) {
+            biometricMessageDeferral.processMessage(1, "test")
+        }
+
+        // THEN deferredMessage will return the string associated with the deferred msgId
+        assertEquals("test", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testReturnsMostFrequentDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+        // WHEN there's two msgId=1 processed and one msgId=2 processed
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(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 = BiometricMessageDeferral(setOf(), setOf(1))
+
+        // WHEN more nonDeferredMessages are shown than the deferred message
+        val totalMessages = 10
+        val nonDeferredMessagesCount =
+            (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+        for (i in 0 until nonDeferredMessagesCount) {
+            biometricMessageDeferral.processMessage(4, "non-deferred-msg")
+        }
+        for (i in nonDeferredMessagesCount until totalMessages) {
+            biometricMessageDeferral.processMessage(1, "msgId-1")
+        }
+
+        // THEN there's no deferred message because it didn't meet the threshold
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testDeferredMessage_manyExcludedMessages_getDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1))
+
+        // WHEN more excludedMessages are shown than the deferred message
+        val totalMessages = 10
+        val excludedMessagesCount = (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+        for (i in 0 until excludedMessagesCount) {
+            biometricMessageDeferral.processMessage(3, "excluded-msg")
+        }
+        for (i in excludedMessagesCount until totalMessages) {
+            biometricMessageDeferral.processMessage(1, "msgId-1")
+        }
+
+        // THEN there IS a deferred message because the deferred msg meets the threshold amongst the
+        // non-excluded messages
+        assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testResetClearsOutCounts() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+        // GIVEN two msgId=1 events processed
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+
+        // WHEN counts are reset and then a single deferred message is processed (msgId=2)
+        biometricMessageDeferral.reset()
+        biometricMessageDeferral.processMessage(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 = BiometricMessageDeferral(setOf(3), 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))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
index 3ac28c8..2af0557 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/charging/WiredChargingRippleControllerTest.kt
@@ -107,11 +107,11 @@
 
         reset(rippleView)
         captor.value.onThemeChanged()
-        verify(rippleView).setColor(ArgumentMatchers.anyInt())
+        verify(rippleView).setColor(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
 
         reset(rippleView)
         captor.value.onUiModeChanged()
-        verify(rippleView).setColor(ArgumentMatchers.anyInt())
+        verify(rippleView).setColor(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/charging/WirelessChargingRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/charging/WirelessChargingRippleControllerTest.kt
deleted file mode 100644
index d967b59..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/charging/WirelessChargingRippleControllerTest.kt
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.charging
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
-import androidx.test.filters.SmallTest
-import com.android.internal.logging.testing.UiEventLoggerFake
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.logcatLogBuffer
-import com.android.systemui.ripple.RippleShader.RippleShape
-import com.android.systemui.util.concurrency.FakeExecutor
-import com.android.systemui.util.time.FakeSystemClock
-import com.google.common.truth.Truth.assertThat
-import junit.framework.Assert.assertEquals
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
-class WirelessChargingRippleControllerTest : SysuiTestCase() {
-
-    private val duration: Long = 1000L
-    private val fakeSystemClock: FakeSystemClock = FakeSystemClock()
-    private lateinit var wirelessChargingRippleController: WirelessChargingRippleController
-    private val fakeExecutor = FakeExecutor(fakeSystemClock)
-
-    @Before
-    fun setUp() {
-        wirelessChargingRippleController = WirelessChargingRippleController(
-                context, UiEventLoggerFake(), fakeExecutor, logcatLogBuffer())
-        fakeSystemClock.setElapsedRealtime(0L)
-    }
-
-    @Test
-    fun showWirelessChargingView_hasCorrectDuration() {
-        val wirelessChargingView = WirelessChargingView.create(
-                context, UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, false,
-                RippleShape.ROUNDED_BOX, duration
-        )
-
-        wirelessChargingRippleController.show(wirelessChargingView, 0)
-        fakeExecutor.runAllReady()
-
-        assertEquals(duration, wirelessChargingView.duration)
-    }
-
-    @Test
-    fun showWirelessChargingView_triggerWhilePlayingAnim_doesNotShowRipple() {
-        val wirelessChargingViewFirst = WirelessChargingView.create(
-                context, UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, false,
-                RippleShape.ROUNDED_BOX, duration
-        )
-        wirelessChargingRippleController.show(wirelessChargingViewFirst, 0)
-        assertThat(fakeExecutor.numPending()).isEqualTo(2)
-        fakeExecutor.runNextReady() // run showInternal
-
-        // ensure we haven't run hideInternal, to simulate the first one is still playing.
-        assertThat(fakeExecutor.numPending()).isEqualTo(1)
-
-        val wirelessChargingViewSecond = WirelessChargingView.create(
-                context, UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, false,
-                RippleShape.ROUNDED_BOX, duration
-        )
-        wirelessChargingRippleController.show(wirelessChargingViewSecond, 0)
-
-        assertEquals(wirelessChargingViewFirst,
-                wirelessChargingRippleController.wirelessChargingView)
-    }
-
-    @Test
-    fun hideWirelessChargingView_afterDuration() {
-        fakeSystemClock.setElapsedRealtime(0L)
-        val wirelessChargingView = WirelessChargingView.create(
-                context, UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, false,
-                RippleShape.ROUNDED_BOX, duration
-        )
-        wirelessChargingRippleController.show(wirelessChargingView, 0)
-
-        assertThat(fakeExecutor.numPending()).isEqualTo(2)
-        with(fakeExecutor) {
-            runNextReady() // run showInternal
-            advanceClockToNext()
-            runNextReady() // run hideInternal
-        }
-
-        assertEquals(null, wirelessChargingRippleController.wirelessChargingView)
-    }
-
-    @Test
-    fun showWirelessChargingView_withCallback_triggersCallback() {
-        val callback = object : WirelessChargingRippleController.Callback {
-            var onAnimationStartingCalled = false
-            var onAnimationEndedCalled = false
-
-            override fun onAnimationStarting() {
-                onAnimationStartingCalled = true
-            }
-
-            override fun onAnimationEnded() {
-                onAnimationEndedCalled = true
-            }
-        }
-        val wirelessChargingView = WirelessChargingView.create(
-                context, UNKNOWN_BATTERY_LEVEL, UNKNOWN_BATTERY_LEVEL, false,
-                RippleShape.CIRCLE, duration
-        )
-        wirelessChargingRippleController.show(wirelessChargingView, 0, callback)
-        assertThat(fakeExecutor.numPending()).isEqualTo(2)
-
-        fakeExecutor.runNextReady() // run showInternal
-        assertEquals(true, callback.onAnimationStartingCalled)
-
-        fakeExecutor.advanceClockToNext()
-
-        fakeExecutor.runNextReady() // run hideInternal
-        assertEquals(true, callback.onAnimationEndedCalled)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.kt
new file mode 100644
index 0000000..1040ec4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/CutoutDecorProviderFactoryTest.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.decor
+
+import android.graphics.Insets
+import android.graphics.Rect
+import android.testing.AndroidTestingRunner
+import android.testing.TestableResources
+import android.util.RotationUtils
+import android.util.Size
+import android.view.Display
+import android.view.DisplayCutout
+import android.view.DisplayCutout.BOUNDS_POSITION_LENGTH
+import android.view.DisplayInfo
+import android.view.Surface
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import org.junit.Assert
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.doAnswer
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class CutoutDecorProviderFactoryTest : SysuiTestCase() {
+
+    @Mock private lateinit var display: Display
+    private var testableRes: TestableResources? = null
+    private lateinit var factory: CutoutDecorProviderFactory
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        testableRes = mContext.orCreateTestableResources
+        factory = CutoutDecorProviderFactory(testableRes!!.resources, display)
+    }
+
+    private fun setupFillCutout(fillCutout: Boolean) {
+        testableRes!!.addOverride(
+            com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout
+        )
+    }
+
+    private fun setupDisplayInfo(
+        displayCutout: DisplayCutout? = null,
+        @Surface.Rotation rotation: Int = Surface.ROTATION_0,
+        displayId: Int = -1
+    ) {
+        doAnswer {
+            it.getArgument<DisplayInfo>(0).let { info ->
+                info.displayCutout = displayCutout
+                info.rotation = rotation
+                info.displayId = displayId
+            }
+            true
+        }.`when`(display).getDisplayInfo(any<DisplayInfo>())
+    }
+
+    private fun getCutout(
+        safeInsets: Insets,
+        cutoutBounds: Array<Rect?>,
+        @Surface.Rotation rotation: Int = Surface.ROTATION_0,
+        cutoutParentSizeForRotate: Size = Size(100, 200)
+    ): DisplayCutout {
+        val insets = RotationUtils.rotateInsets(safeInsets, rotation)
+        val sorted = arrayOfNulls<Rect>(BOUNDS_POSITION_LENGTH)
+        for (pos in 0 until BOUNDS_POSITION_LENGTH) {
+            val rotatedPos = (pos - rotation + BOUNDS_POSITION_LENGTH) % BOUNDS_POSITION_LENGTH
+            if (cutoutBounds[pos] != null) {
+                RotationUtils.rotateBounds(
+                    cutoutBounds[pos],
+                    cutoutParentSizeForRotate.width,
+                    cutoutParentSizeForRotate.height,
+                    rotation
+                )
+            }
+            sorted[rotatedPos] = cutoutBounds[pos]
+        }
+        return DisplayCutout(
+            insets,
+            sorted[DisplayCutout.BOUNDS_POSITION_LEFT],
+            sorted[DisplayCutout.BOUNDS_POSITION_TOP],
+            sorted[DisplayCutout.BOUNDS_POSITION_RIGHT],
+            sorted[DisplayCutout.BOUNDS_POSITION_BOTTOM]
+        )
+    }
+
+    @Test
+    fun testGetNothingIfNoCutout() {
+        setupFillCutout(false)
+
+        Assert.assertFalse(factory.hasProviders)
+        Assert.assertEquals(0, factory.providers.size)
+    }
+
+    @Test
+    fun testGetTopCutoutProvider() {
+        setupFillCutout(true)
+        setupDisplayInfo(
+            getCutout(
+                safeInsets = Insets.of(0, 1, 0, 0),
+                cutoutBounds = arrayOf(null, Rect(9, 0, 10, 1), null, null)
+            )
+        )
+
+        Assert.assertTrue(factory.hasProviders)
+
+        val providers = factory.providers
+        Assert.assertEquals(1, providers.size)
+        Assert.assertEquals(1, providers[0].numOfAlignedBound)
+        Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_TOP, providers[0].alignedBounds[0])
+    }
+
+    @Test
+    fun testGetBottomCutoutProviderOnLandscape() {
+        setupFillCutout(true)
+        setupDisplayInfo(
+            getCutout(
+                safeInsets = Insets.of(0, 0, 0, 1),
+                cutoutBounds = arrayOf(null, null, null, Rect(45, 199, 55, 200)),
+                rotation = Surface.ROTATION_90
+            ),
+            Surface.ROTATION_90
+        )
+
+        Assert.assertTrue(factory.hasProviders)
+
+        val providers = factory.providers
+        Assert.assertEquals(1, providers.size)
+        Assert.assertEquals(1, providers[0].numOfAlignedBound)
+        Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_BOTTOM, providers[0].alignedBounds[0])
+    }
+
+    @Test
+    fun testGetLeftCutoutProviderOnSeascape() {
+        setupFillCutout(true)
+        setupDisplayInfo(
+            getCutout(
+                safeInsets = Insets.of(1, 0, 0, 0),
+                cutoutBounds = arrayOf(Rect(0, 20, 1, 40), null, null, null),
+                rotation = Surface.ROTATION_270
+            ),
+            Surface.ROTATION_270
+        )
+
+        Assert.assertTrue(factory.hasProviders)
+
+        val providers = factory.providers
+        Assert.assertEquals(1, providers.size)
+        Assert.assertEquals(1, providers[0].numOfAlignedBound)
+        Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_LEFT, providers[0].alignedBounds[0])
+    }
+
+    @Test
+    fun testGetTopRightCutoutProviderOnReverse() {
+        setupFillCutout(true)
+        setupDisplayInfo(
+            getCutout(
+                safeInsets = Insets.of(0, 1, 1, 0),
+                cutoutBounds = arrayOf(
+                    null,
+                    Rect(9, 0, 10, 1),
+                    Rect(99, 40, 100, 60),
+                    null
+                ),
+                rotation = Surface.ROTATION_180
+            ),
+            Surface.ROTATION_180
+        )
+
+        Assert.assertTrue(factory.hasProviders)
+
+        val providers = factory.providers
+        Assert.assertEquals(2, providers.size)
+        Assert.assertEquals(1, providers[0].numOfAlignedBound)
+        Assert.assertEquals(1, providers[1].numOfAlignedBound)
+        providers.sortedBy { it.alignedBounds[0] }.let {
+            Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_TOP, it[0].alignedBounds[0])
+            Assert.assertEquals(DisplayCutout.BOUNDS_POSITION_RIGHT, it[1].alignedBounds[0])
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index abe7ae1..6a55a60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -448,7 +448,7 @@
 
     @Test
     public void testWakeUp_wakesUp() {
-        mMachine.wakeUp();
+        mMachine.wakeUp(DozeLog.REASON_SENSOR_PICKUP);
 
         assertTrue(mServiceFake.requestedWakeup);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
index 903e4a1..6b3ec68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
@@ -75,9 +75,9 @@
     }
 
     @Test
-    public void forwards_requestWakeUp() throws Exception {
-        mWrapper.requestWakeUp();
-        verify(mInner).requestWakeUp();
+    public void forwards_requestWakeUp() {
+        mWrapper.requestWakeUp(DozeLog.REASON_SENSOR_PICKUP);
+        verify(mInner).requestWakeUp(DozeLog.REASON_SENSOR_PICKUP);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
index 75f97a2..928b314 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeServiceFake.java
@@ -48,7 +48,7 @@
     }
 
     @Override
-    public void requestWakeUp() {
+    public void requestWakeUp(@DozeLog.Reason int reason) {
         requestedWakeup = true;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
index fac58a0..9ae7217 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
@@ -81,9 +81,9 @@
     }
 
     @Test
-    public void forwards_requestWakeUp() throws Exception {
-        mWrapper.requestWakeUp();
-        verify(mInner).requestWakeUp();
+    public void forwards_requestWakeUp() {
+        mWrapper.requestWakeUp(DozeLog.REASON_SENSOR_PICKUP);
+        verify(mInner).requestWakeUp(DozeLog.REASON_SENSOR_PICKUP);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 01a1a37..6436981 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.StatusBarManager;
 import android.hardware.Sensor;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.testing.AndroidTestingRunner;
@@ -40,12 +41,14 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent;
+import com.android.systemui.log.SessionTracker;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.policy.DevicePostureController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -92,12 +95,14 @@
     private KeyguardStateController mKeyguardStateController;
     @Mock
     private DevicePostureController mDevicePostureController;
+    @Mock
+    private SessionTracker mSessionTracker;
 
     private DozeTriggers mTriggers;
     private FakeSensorManager mSensors;
     private Sensor mTapSensor;
     private FakeProximitySensor mProximitySensor;
-    private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+    private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
 
     @Before
     public void setUp() throws Exception {
@@ -123,14 +128,14 @@
         mTriggers = new DozeTriggers(mContext, mHost, config, dozeParameters,
                 asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
                 mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(),
-                mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController,
+                mAuthController, mUiEventLogger, mSessionTracker, mKeyguardStateController,
                 mDevicePostureController);
         mTriggers.setDozeMachine(mMachine);
         waitForSensorManager();
     }
 
     @Test
-    public void testOnNotification_stillWorksAfterOneFailedProxCheck() throws Exception {
+    public void testOnNotification_stillWorksAfterOneFailedProxCheck() {
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
         ArgumentCaptor<DozeHost.Callback> captor = ArgumentCaptor.forClass(DozeHost.Callback.class);
         doAnswer(invocation -> null).when(mHost).addCallback(captor.capture());
@@ -216,7 +221,7 @@
     }
 
     @Test
-    public void testProximitySensorNotAvailablel() {
+    public void testProximitySensorNotAvailable() {
         mProximitySensor.setSensorAvailable(false);
         mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_LONG_PRESS, 100, 100, null);
         mTriggers.onSensor(DozeLog.PULSE_REASON_SENSOR_WAKE_REACH, 100, 100,
@@ -228,6 +233,9 @@
     public void testQuickPickup() {
         // GIVEN device is in doze (screen blank, but running doze sensors)
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+        InstanceId keyguardSessionId = InstanceId.fakeInstanceId(99);
+        when(mSessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD))
+                .thenReturn(keyguardSessionId);
 
         // WHEN quick pick up is triggered
         mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null);
@@ -236,7 +244,8 @@
         verify(mMachine).requestPulse(anyInt());
 
         // THEN a log is taken that quick pick up was triggered
-        verify(mUiEventLogger).log(DozingUpdateUiEvent.DOZING_UPDATE_QUICK_PICKUP);
+        verify(mUiEventLogger)
+                .log(DozingUpdateUiEvent.DOZING_UPDATE_QUICK_PICKUP, keyguardSessionId);
     }
 
     @Test
@@ -249,7 +258,7 @@
         mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
 
         // THEN wakeup
-        verify(mMachine).wakeUp();
+        verify(mMachine).wakeUp(DozeLog.REASON_SENSOR_PICKUP);
     }
 
     @Test
@@ -262,7 +271,7 @@
         mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
 
         // THEN never wakeup
-        verify(mMachine, never()).wakeUp();
+        verify(mMachine, never()).wakeUp(DozeLog.REASON_SENSOR_PICKUP);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java
new file mode 100644
index 0000000..bc94440
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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.dreams.complication;
+
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.media.dream.MediaDreamComplication;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
[email protected]
+public class DreamMediaEntryComplicationTest extends SysuiTestCase {
+    @Mock
+    private View mView;
+
+    @Mock
+    private DreamOverlayStateController mDreamOverlayStateController;
+
+    @Mock
+    private MediaDreamComplication mMediaComplication;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    /**
+     * Ensures clicking media entry chip adds/removes media complication.
+     */
+    @Test
+    public void testClick() {
+        final DreamMediaEntryComplication.DreamMediaEntryViewController viewController =
+                new DreamMediaEntryComplication.DreamMediaEntryViewController(
+                        mView,
+                        mDreamOverlayStateController,
+                        mMediaComplication);
+
+        final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mView).setOnClickListener(clickListenerCaptor.capture());
+
+        clickListenerCaptor.getValue().onClick(mView);
+        verify(mView).setSelected(true);
+        verify(mDreamOverlayStateController).addComplication(mMediaComplication);
+        clickListenerCaptor.getValue().onClick(mView);
+        verify(mView).setSelected(false);
+        verify(mDreamOverlayStateController).removeComplication(mMediaComplication);
+    }
+
+    /**
+     * Ensures media complication is removed when the view is detached.
+     */
+    @Test
+    public void testOnViewDetached() {
+        final DreamMediaEntryComplication.DreamMediaEntryViewController viewController =
+                new DreamMediaEntryComplication.DreamMediaEntryViewController(
+                        mView,
+                        mDreamOverlayStateController,
+                        mMediaComplication);
+
+        viewController.onViewDetached();
+        verify(mView).setSelected(false);
+        verify(mDreamOverlayStateController).removeComplication(mMediaComplication);
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
index 7d54758..fa8f88a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/SmartSpaceComplicationTest.java
@@ -43,7 +43,7 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.Arrays;
+import java.util.Collections;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -61,9 +61,6 @@
     private SmartSpaceComplication mComplication;
 
     @Mock
-    private ComplicationViewModel mComplicationViewModel;
-
-    @Mock
     private View mBcSmartspaceView;
 
     @Before
@@ -125,12 +122,12 @@
 
         // Test
         final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
-        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
+        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.singletonList(target));
         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
     }
 
     @Test
-    public void testOverlayActive_targetsEmpty_removesComplication() {
+    public void testOverlayActive_targetsEmpty_addsComplication() {
         final SmartSpaceComplication.Registrant registrant = getRegistrant();
         registrant.start();
 
@@ -145,13 +142,9 @@
                 ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
         verify(mSmartspaceController).addListener(listenerCaptor.capture());
 
-        final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
-        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
-        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
-
         // Test
-        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList());
-        verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
+        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.emptyList());
+        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
     }
 
     @Test
@@ -170,8 +163,7 @@
                 ArgumentCaptor.forClass(BcSmartspaceDataPlugin.SmartspaceTargetListener.class);
         verify(mSmartspaceController).addListener(listenerCaptor.capture());
 
-        final SmartspaceTarget target = Mockito.mock(SmartspaceTarget.class);
-        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Arrays.asList(target));
+        listenerCaptor.getValue().onSmartspaceTargetsUpdated(Collections.emptyList());
         verify(mDreamOverlayStateController).addComplication(eq(mComplication));
 
         // Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
index ff579a1..318f2bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FakeFeatureFlagsTest.kt
@@ -41,7 +41,7 @@
      * specified. If not, an exception is thrown.
      */
     @Test
-    fun throwsIfUnspecifiedFlagIsAccessed() {
+    fun accessingUnspecifiedFlags_throwsException() {
         val flags: FeatureFlags = FakeFeatureFlags()
         try {
             assertThat(flags.isEnabled(Flags.TEAMFOOD)).isFalse()
@@ -88,7 +88,7 @@
     }
 
     @Test
-    fun specifiedFlagsReturnCorrectValues() {
+    fun specifiedFlags_returnCorrectValues() {
         val flags = FakeFeatureFlags()
         flags.set(unreleasedFlag, false)
         flags.set(releasedFlag, false)
@@ -114,4 +114,125 @@
         assertThat(flags.isEnabled(sysPropBooleanFlag)).isTrue()
         assertThat(flags.getString(resourceStringFlag)).isEqualTo("Android")
     }
+
+    @Test
+    fun listenerForBooleanFlag_calledOnlyWhenFlagChanged() {
+        val flags = FakeFeatureFlags()
+        val listener = VerifyingListener()
+        flags.addListener(unreleasedFlag, listener)
+
+        flags.set(unreleasedFlag, true)
+        flags.set(unreleasedFlag, true)
+        flags.set(unreleasedFlag, false)
+        flags.set(unreleasedFlag, false)
+
+        listener.verifyInOrder(unreleasedFlag.id, unreleasedFlag.id)
+    }
+
+    @Test
+    fun listenerForStringFlag_calledOnlyWhenFlagChanged() {
+        val flags = FakeFeatureFlags()
+        val listener = VerifyingListener()
+        flags.addListener(stringFlag, listener)
+
+        flags.set(stringFlag, "Test")
+        flags.set(stringFlag, "Test")
+
+        listener.verifyInOrder(stringFlag.id)
+    }
+
+    @Test
+    fun listenerForBooleanFlag_notCalledAfterRemoved() {
+        val flags = FakeFeatureFlags()
+        val listener = VerifyingListener()
+        flags.addListener(unreleasedFlag, listener)
+        flags.set(unreleasedFlag, true)
+        flags.removeListener(listener)
+        flags.set(unreleasedFlag, false)
+
+        listener.verifyInOrder(unreleasedFlag.id)
+    }
+
+    @Test
+    fun listenerForStringFlag_notCalledAfterRemoved() {
+        val flags = FakeFeatureFlags()
+        val listener = VerifyingListener()
+
+        flags.addListener(stringFlag, listener)
+        flags.set(stringFlag, "Test")
+        flags.removeListener(listener)
+        flags.set(stringFlag, "Other")
+
+        listener.verifyInOrder(stringFlag.id)
+    }
+
+    @Test
+    fun listenerForMultipleFlags_calledWhenFlagsChange() {
+        val flags = FakeFeatureFlags()
+        val listener = VerifyingListener()
+        flags.addListener(unreleasedFlag, listener)
+        flags.addListener(releasedFlag, listener)
+
+        flags.set(releasedFlag, true)
+        flags.set(unreleasedFlag, true)
+
+        listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id)
+    }
+
+    @Test
+    fun listenerForMultipleFlags_notCalledAfterRemoved() {
+        val flags = FakeFeatureFlags()
+        val listener = VerifyingListener()
+
+        flags.addListener(unreleasedFlag, listener)
+        flags.addListener(releasedFlag, listener)
+        flags.set(releasedFlag, true)
+        flags.set(unreleasedFlag, true)
+        flags.removeListener(listener)
+        flags.set(releasedFlag, false)
+        flags.set(unreleasedFlag, false)
+
+        listener.verifyInOrder(releasedFlag.id, unreleasedFlag.id)
+    }
+
+    @Test
+    fun multipleListenersForSingleFlag_allAreCalledWhenChanged() {
+        val flags = FakeFeatureFlags()
+        val listener1 = VerifyingListener()
+        val listener2 = VerifyingListener()
+        flags.addListener(releasedFlag, listener1)
+        flags.addListener(releasedFlag, listener2)
+
+        flags.set(releasedFlag, true)
+
+        listener1.verifyInOrder(releasedFlag.id)
+        listener2.verifyInOrder(releasedFlag.id)
+    }
+
+    @Test
+    fun multipleListenersForSingleFlag_removedListenerNotCalledAfterRemoval() {
+        val flags = FakeFeatureFlags()
+        val listener1 = VerifyingListener()
+        val listener2 = VerifyingListener()
+        flags.addListener(releasedFlag, listener1)
+        flags.addListener(releasedFlag, listener2)
+
+        flags.set(releasedFlag, true)
+        flags.removeListener(listener2)
+        flags.set(releasedFlag, false)
+
+        listener1.verifyInOrder(releasedFlag.id, releasedFlag.id)
+        listener2.verifyInOrder(releasedFlag.id)
+    }
+
+    class VerifyingListener : FlagListenable.Listener {
+        var flagEventIds = mutableListOf<Int>()
+        override fun onFlagChanged(event: FlagListenable.FlagEvent) {
+            flagEventIds.add(event.flagId)
+        }
+
+        fun verifyInOrder(vararg eventIds: Int) {
+            assertThat(flagEventIds).containsExactlyElementsIn(eventIds.asList())
+        }
+    }
 }
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..eecbee5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
@@ -27,11 +27,11 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor.forClass
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
@@ -218,4 +218,18 @@
         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(
+                remoteAnimationTarget,
+                0 /* startTime */,
+                false /* requestedShowSurfaceBehindKeyguard */
+        )
+
+        assertTrue(keyguardUnlockAnimationController.isPlayingCannedUnlockAnimation())
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index 6e89bb9..21c018a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -48,7 +48,6 @@
 import com.android.keyguard.KeyguardDisplayManager;
 import com.android.keyguard.KeyguardSecurityView;
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.logging.KeyguardViewMediatorLogger;
 import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -107,7 +106,6 @@
     private @Mock Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy;
     private @Mock DreamOverlayStateController mDreamOverlayStateController;
     private @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
-    private @Mock KeyguardViewMediatorLogger mLogger;
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
@@ -264,8 +262,7 @@
                 mInteractionJankMonitor,
                 mDreamOverlayStateController,
                 mNotificationShadeWindowControllerLazy,
-                () -> mActivityLaunchAnimator,
-                mLogger);
+                () -> mActivityLaunchAnimator);
         mViewMediator.start();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index 5ec6bdf..27a5190 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -32,7 +32,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.PointF;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.AnimatedStateListDrawable;
 import android.hardware.biometrics.BiometricSourceType;
@@ -127,7 +127,7 @@
             ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
     private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
 
-    @Captor private ArgumentCaptor<PointF> mPointCaptor;
+    @Captor private ArgumentCaptor<Point> mPointCaptor;
 
     @Before
     public void setUp() throws Exception {
@@ -178,7 +178,7 @@
     @Test
     public void testUpdateFingerprintLocationOnInit() {
         // GIVEN fp sensor location is available pre-attached
-        Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
+        Pair<Float, Point> udfps = setupUdfps(); // first = radius, second = udfps location
 
         // WHEN lock icon view controller is initialized and attached
         mLockIconViewController.init();
@@ -193,7 +193,7 @@
     @Test
     public void testUpdatePaddingBasedOnResolutionScale() {
         // GIVEN fp sensor location is available pre-attached & scaled resolution factor is 5
-        Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
+        Pair<Float, Point> udfps = setupUdfps(); // first = radius, second = udfps location
         when(mAuthController.getScaleFactor()).thenReturn(5f);
 
         // WHEN lock icon view controller is initialized and attached
@@ -218,7 +218,7 @@
 
         // GIVEN fp sensor location is available post-attached
         captureAuthControllerCallback();
-        Pair<Float, PointF> udfps = setupUdfps();
+        Pair<Float, Point> udfps = setupUdfps();
 
         // WHEN all authenticators are registered
         mAuthControllerCallback.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT);
@@ -241,7 +241,7 @@
 
         // GIVEN fp sensor location is available post-attached
         captureAuthControllerCallback();
-        Pair<Float, PointF> udfps = setupUdfps();
+        Pair<Float, Point> udfps = setupUdfps();
 
         // WHEN udfps location changes
         mAuthControllerCallback.onUdfpsLocationChanged();
@@ -421,9 +421,9 @@
         verify(mLockIconView).setTranslationX(0);
 
     }
-    private Pair<Float, PointF> setupUdfps() {
+    private Pair<Float, Point> setupUdfps() {
         when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
-        final PointF udfpsLocation = new PointF(50, 75);
+        final Point udfpsLocation = new Point(50, 75);
         final float radius = 33f;
         when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocation);
         when(mAuthController.getUdfpsRadius()).thenReturn(radius);
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 3aa22669..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/log/LogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
index 7b12eb7..56aff3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
@@ -41,18 +41,6 @@
     }
 
     @Test
-    fun log_shouldSaveLogToBufferWithException() {
-        val exception = createTestException("Some exception test message", "SomeExceptionTestClass")
-        buffer.log("Test", LogLevel.INFO, "Some test message", exception)
-
-        val dumpedString = dumpBuffer()
-
-        assertThat(dumpedString).contains("Some test message")
-        assertThat(dumpedString).contains("Some exception test message")
-        assertThat(dumpedString).contains("SomeExceptionTestClass")
-    }
-
-    @Test
     fun log_shouldRotateIfLogBufferIsFull() {
         buffer.log("Test", LogLevel.INFO, "This should be rotated")
         buffer.log("Test", LogLevel.INFO, "New test message")
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 219b3c8..5a50a9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -28,18 +28,24 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
 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
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
-import javax.inject.Provider
 
 private val DATA = MediaTestUtils.emptyMediaData
 
@@ -64,6 +70,14 @@
     @Mock lateinit var dumpManager: DumpManager
     @Mock lateinit var logger: MediaUiEventLogger
     @Mock lateinit var debugLogger: MediaCarouselControllerLogger
+    @Mock lateinit var mediaViewHolder: MediaViewHolder
+    @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
@@ -87,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()
     }
 
@@ -258,4 +275,103 @@
 
         verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testSetSquishinessFractionForMedia_setPlayerBottom() {
+        whenever(panel.mediaViewHolder).thenReturn(mediaViewHolder)
+        whenever(mediaViewHolder.player).thenReturn(player)
+        whenever(player.measuredHeight).thenReturn(100)
+
+        val playingLocal = Triple("playing local",
+                DATA.copy(active = true, isPlaying = true,
+                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
+                4500L)
+        MediaPlayerData.addMediaPlayer(playingLocal.first, playingLocal.second, panel, clock,
+                false, debugLogger)
+
+        mediaCarouselController.squishinessFraction = 0.0f
+        verify(player).bottom = 50
+        verifyNoMoreInteractions(recommendationViewHolder)
+
+        mediaCarouselController.squishinessFraction = 0.5f
+        verify(player).bottom = 75
+        verifyNoMoreInteractions(recommendationViewHolder)
+    }
+
+    @Test
+    fun testSetSquishinessFractionForRecommendation_setPlayerBottom() {
+        whenever(panel.recommendationViewHolder).thenReturn(recommendationViewHolder)
+        whenever(recommendationViewHolder.recommendations).thenReturn(recommendations)
+        whenever(recommendations.measuredHeight).thenReturn(100)
+
+        MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
+                false, clock)
+
+        mediaCarouselController.squishinessFraction = 0.0f
+        verifyNoMoreInteractions(mediaViewHolder)
+        verify(recommendationViewHolder.recommendations).bottom = 50
+
+        mediaCarouselController.squishinessFraction = 0.5f
+        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/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 1785022..bef4695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -1051,6 +1051,17 @@
     }
 
     @Test
+    fun bindDeviceWithNullName() {
+        val fallbackString = context.getResources().getString(R.string.media_seamless_other_device)
+        player.attachPlayer(viewHolder)
+        val state = mediaData.copy(device = device.copy(name = null))
+        player.bindPlayer(state, PACKAGE)
+        assertThat(seamless.isEnabled()).isTrue()
+        assertThat(seamlessText.getText()).isEqualTo(fallbackString)
+        assertThat(seamless.contentDescription).isEqualTo(fallbackString)
+    }
+
+    @Test
     fun bindDeviceResumptionPlayer() {
         player.attachPlayer(viewHolder)
         val state = mediaData.copy(resumption = true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index d1ed8e9..f9c7d2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -31,7 +31,6 @@
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
@@ -108,6 +107,7 @@
     private val clock = FakeSystemClock()
     @Mock private lateinit var tunerService: TunerService
     @Captor lateinit var tunableCaptor: ArgumentCaptor<TunerService.Tunable>
+    @Captor lateinit var callbackCaptor: ArgumentCaptor<(String, PlaybackState) -> Unit>
 
     private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20)
 
@@ -974,7 +974,6 @@
     fun testPlaybackStateChange_keyExists_callsListener() {
         // Notification has been added
         addNotificationAndLoad()
-        val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>()
         verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
 
         // Callback gets an updated state
@@ -992,7 +991,6 @@
     @Test
     fun testPlaybackStateChange_keyDoesNotExist_doesNothing() {
         val state = PlaybackState.Builder().build()
-        val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>()
         verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
 
         // No media added with this key
@@ -1013,7 +1011,6 @@
 
         // And then get a state update
         val state = PlaybackState.Builder().build()
-        val callbackCaptor = argumentCaptor<(String, PlaybackState) -> Unit>()
         verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
 
         // Then no changes are made
@@ -1022,6 +1019,83 @@
             anyBoolean())
     }
 
+    @Test
+    fun testPlaybackState_PauseWhenFlagTrue_keyExists_callsListener() {
+        whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
+        val state = PlaybackState.Builder()
+                .setState(PlaybackState.STATE_PAUSED, 0L, 1f)
+                .build()
+        whenever(controller.playbackState).thenReturn(state)
+
+        addNotificationAndLoad()
+        verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
+        callbackCaptor.value.invoke(KEY, state)
+
+        verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY),
+                capture(mediaDataCaptor), eq(true), eq(0), eq(false))
+        assertThat(mediaDataCaptor.value.isPlaying).isFalse()
+        assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
+    }
+
+    @Test
+    fun testPlaybackState_PauseStateAfterAddingResumption_keyExists_callsListener() {
+        val desc = MediaDescription.Builder().run {
+            setTitle(SESSION_TITLE)
+            build()
+        }
+        val state = PlaybackState.Builder()
+                .setState(PlaybackState.STATE_PAUSED, 0L, 1f)
+                .setActions(PlaybackState.ACTION_PLAY_PAUSE)
+                .build()
+
+        // Add resumption controls in order to have semantic actions.
+        // To make sure that they are not null after changing state.
+        mediaDataManager.addResumptionControls(
+                USER_ID,
+                desc,
+                Runnable {},
+                session.sessionToken,
+                APP_NAME,
+                pendingIntent,
+                PACKAGE_NAME
+        )
+        backgroundExecutor.runAllReady()
+        foregroundExecutor.runAllReady()
+
+        verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
+        callbackCaptor.value.invoke(PACKAGE_NAME, state)
+
+        verify(listener)
+                .onMediaDataLoaded(
+                        eq(PACKAGE_NAME),
+                        eq(PACKAGE_NAME),
+                        capture(mediaDataCaptor),
+                        eq(true),
+                        eq(0),
+                        eq(false)
+                )
+        assertThat(mediaDataCaptor.value.isPlaying).isFalse()
+        assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
+    }
+
+    @Test
+    fun testPlaybackStateNull_Pause_keyExists_callsListener() {
+        whenever(controller.playbackState).thenReturn(null)
+        val state = PlaybackState.Builder()
+                .setState(PlaybackState.STATE_PAUSED, 0L, 1f)
+                .setActions(PlaybackState.ACTION_PLAY_PAUSE)
+                .build()
+
+        addNotificationAndLoad()
+        verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
+        callbackCaptor.value.invoke(KEY, state)
+
+        verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY),
+                capture(mediaDataCaptor), eq(true), eq(0), eq(false))
+        assertThat(mediaDataCaptor.value.isPlaying).isFalse()
+        assertThat(mediaDataCaptor.value.semanticActions).isNull()
+    }
+
     /**
      * Helper function to add a media notification and capture the resulting MediaData
      */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index ee10426..121c894 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -59,8 +59,8 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 private const val KEY = "TEST_KEY"
 private const val KEY_OLD = "TEST_KEY_OLD"
@@ -402,9 +402,10 @@
         manager.onMediaDataLoaded(KEY, null, mediaData)
         fakeBgExecutor.runAllReady()
         fakeFgExecutor.runAllReady()
-        // THEN the device is disabled
+        // THEN the device is disabled and name is set to null
         val data = captureDeviceData(KEY)
         assertThat(data.enabled).isFalse()
+        assertThat(data.name).isNull()
     }
 
     @Test
@@ -421,9 +422,10 @@
         deviceCallback.onSelectedDeviceStateChanged(device, 1)
         fakeBgExecutor.runAllReady()
         fakeFgExecutor.runAllReady()
-        // THEN the device is disabled
+        // THEN the device is disabled and name is set to null
         val data = captureDeviceData(KEY)
         assertThat(data.enabled).isFalse()
+        assertThat(data.name).isNull()
     }
 
     @Test
@@ -440,9 +442,24 @@
         deviceCallback.onDeviceListUpdate(mutableListOf(device))
         fakeBgExecutor.runAllReady()
         fakeFgExecutor.runAllReady()
-        // THEN the device is disabled
+        // THEN the device is disabled and name is set to null
         val data = captureDeviceData(KEY)
         assertThat(data.enabled).isFalse()
+        assertThat(data.name).isNull()
+    }
+
+    @Test
+    fun mr2ReturnsRouteWithNullName_useLocalDeviceName() {
+        // GIVEN that MR2Manager returns a routing session that does not have a name
+        whenever(route.name).thenReturn(null)
+        // WHEN a notification is added
+        manager.onMediaDataLoaded(KEY, null, mediaData)
+        fakeBgExecutor.runAllReady()
+        fakeFgExecutor.runAllReady()
+        // THEN the device is enabled and uses the current connected device name
+        val data = captureDeviceData(KEY)
+        assertThat(data.name).isEqualTo(DEVICE_NAME)
+        assertThat(data.enabled).isTrue()
     }
 
     @Test
@@ -647,12 +664,14 @@
             override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
             override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
             override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {}
-            override fun onBroadcastMetadataChanged(broadcastId: Int,
-                                                    metadata: BluetoothLeBroadcastMetadata) {}
+            override fun onBroadcastMetadataChanged(
+                broadcastId: Int,
+                metadata: BluetoothLeBroadcastMetadata
+            ) {}
         }
 
         bluetoothLeBroadcast.registerCallback(fakeFgExecutor, callback)
-        return callback;
+        return callback
     }
 
     fun setupLeAudioConfiguration(isLeAudio: Boolean) {
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/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 6173692..9be201e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -224,6 +224,14 @@
     }
 
     @Test
+    public void refresh_inDragging_directSetRefreshingToFalse() {
+        when(mMediaOutputBaseAdapter.isDragging()).thenReturn(true);
+        mMediaOutputBaseDialogImpl.refresh();
+
+        assertThat(mMediaOutputController.isRefreshing()).isFalse();
+    }
+
+    @Test
     public void refresh_notInDragging_verifyUpdateAdapter() {
         when(mMediaOutputBaseAdapter.getCurrentActivePosition()).thenReturn(-1);
         when(mMediaOutputBaseAdapter.isDragging()).thenReturn(false);
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 c101b9f..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
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
 
+import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
@@ -30,6 +31,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.dreams.complication.DreamMediaEntryComplication;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaData;
 import com.android.systemui.media.MediaDataManager;
@@ -51,7 +53,7 @@
     DreamOverlayStateController mDreamOverlayStateController;
 
     @Mock
-    MediaDreamComplication mComplication;
+    DreamMediaEntryComplication mMediaEntryComplication;
 
     @Mock
     FeatureFlags mFeatureFlags;
@@ -70,13 +72,13 @@
     }
 
     @Test
-    public void testComplicationAddition() {
+    public void testOnMediaDataLoaded_complicationAddition() {
         final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
-                mDreamOverlayStateController, mComplication, mFeatureFlags);
-
+                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);
@@ -85,22 +87,60 @@
         when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
         listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
                 /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
-        verify(mDreamOverlayStateController).addComplication(eq(mComplication));
+        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());
 
         when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
         listener.onMediaDataRemoved(mKey);
-        verify(mDreamOverlayStateController).removeComplication(eq(mComplication));
+        verify(mDreamOverlayStateController).removeComplication(eq(mMediaEntryComplication));
     }
 
     @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,
-                mDreamOverlayStateController, mComplication, mFeatureFlags);
+                mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
 
         sentinel.start();
 
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..e7b4593 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,
@@ -182,7 +178,7 @@
 
     @Test
     fun setIcon_isAppIcon_usesAppIconSize() {
-        controllerReceiver.displayChip(getChipReceiverInfo())
+        controllerReceiver.displayView(getChipReceiverInfo())
         val chipView = getChipView()
 
         controllerReceiver.setIcon(chipView, PACKAGE_NAME)
@@ -198,7 +194,7 @@
 
     @Test
     fun setIcon_notAppIcon_usesGenericIconSize() {
-        controllerReceiver.displayChip(getChipReceiverInfo())
+        controllerReceiver.displayView(getChipReceiverInfo())
         val chipView = getChipView()
 
         controllerReceiver.setIcon(chipView, appPackageName = null)
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..52b6eed 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,
@@ -309,7 +305,7 @@
     @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,26 +564,26 @@
 
     @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())
@@ -596,9 +592,9 @@
     @Test
     fun transferToReceiverTriggeredThenFarFromReceiver_eventuallyTimesOut() {
         val state = transferToReceiverTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
         fakeClock.advanceTime(1000L)
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
 
         fakeClock.advanceTime(TIMEOUT + 1L)
 
@@ -606,11 +602,11 @@
     }
 
     @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())
@@ -619,9 +615,9 @@
     @Test
     fun transferToThisDeviceTriggeredThenFarFromReceiver_eventuallyTimesOut() {
         val state = transferToThisDeviceTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
         fakeClock.advanceTime(1000L)
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
 
         fakeClock.advanceTime(TIMEOUT + 1L)
 
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/QSFragmentDisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
index e2c6ff9..aacc695 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentDisableFlagsLoggerTest.kt
@@ -21,12 +21,12 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.log.LogcatEchoTracker
-import com.android.systemui.statusbar.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
 import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.mockito.Mockito.mock
 import java.io.PrintWriter
 import java.io.StringWriter
+import org.junit.Test
+import org.mockito.Mockito.mock
 
 @SmallTest
 class QSFragmentDisableFlagsLoggerTest : SysuiTestCase() {
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/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index c127a6b..ecc8457 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -44,6 +44,7 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
@@ -86,6 +87,7 @@
     @Mock
     private QSLogger mQSLogger;
     private DumpManager mDumpManager = new DumpManager();
+    private MediaCarouselController mMediaCarouselController;
     @Mock
     QSTileImpl mQSTile;
     @Mock
@@ -108,9 +110,9 @@
         protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
                 QSCustomizerController qsCustomizerController, MediaHost mediaHost,
                 MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-                DumpManager dumpManager) {
+                DumpManager dumpManager, MediaCarouselController mediaCarouselController) {
             super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,
-                    qsLogger, dumpManager);
+                    qsLogger, dumpManager, mediaCarouselController);
         }
 
         @Override
@@ -144,7 +146,7 @@
 
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
 
         mController.init();
         reset(mQSTileRevealController);
@@ -156,7 +158,7 @@
 
         QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
                 mQSTileHost, mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager) {
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController) {
             @Override
             protected QSTileRevealController createTileRevealController() {
                 return mQSTileRevealController;
@@ -249,7 +251,7 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
         mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isTrue();
@@ -258,7 +260,7 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
         mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isFalse();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index c0944efc..98d499a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -6,6 +6,7 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaCarouselController
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.FalsingManager
@@ -27,8 +28,8 @@
 import org.mockito.Mockito.any
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -40,6 +41,7 @@
     @Mock private lateinit var qsCustomizerController: QSCustomizerController
     @Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory
     @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var mediaCarouselController: MediaCarouselController
     @Mock private lateinit var metricsLogger: MetricsLogger
     @Mock private lateinit var uiEventLogger: UiEventLogger
     @Mock private lateinit var qsLogger: QSLogger
@@ -76,6 +78,7 @@
             mediaHost,
             qsTileRevealControllerFactory,
             dumpManager,
+            mediaCarouselController,
             metricsLogger,
             uiEventLogger,
             qsLogger,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index e4f47fd..39f27d4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,6 +23,7 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaCarouselController
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.qs.QSTile
@@ -59,6 +60,7 @@
     @Mock private lateinit var tileLayout: TileLayout
     @Mock private lateinit var tileView: QSTileView
     @Captor private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
+    @Mock private lateinit var mediaCarouselController: MediaCarouselController
 
     private val uiEventLogger = UiEventLoggerFake()
     private val dumpManager = DumpManager()
@@ -88,7 +90,8 @@
                 metricsLogger,
                 uiEventLogger,
                 qsLogger,
-                dumpManager)
+                dumpManager,
+                mediaCarouselController)
 
         controller.init()
     }
@@ -157,7 +160,8 @@
         metricsLogger: MetricsLogger,
         uiEventLogger: UiEventLoggerFake,
         qsLogger: QSLogger,
-        dumpManager: DumpManager
+        dumpManager: DumpManager,
+        mediaCarouselController: MediaCarouselController
     ) :
         QuickQSPanelController(
             view,
@@ -169,7 +173,8 @@
             metricsLogger,
             uiEventLogger,
             qsLogger,
-            dumpManager) {
+            dumpManager,
+            mediaCarouselController) {
 
         private var rotation = RotationUtils.ROTATION_NONE
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index cb4f08e..eb907bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -192,6 +192,14 @@
         verify(view).setIsSingleCarrier(false)
     }
 
+    @Test
+    fun testAlarmIconIgnored() {
+        controller.init()
+
+        verify(iconContainer).addIgnoredSlot(
+                mContext.getString(com.android.internal.R.string.status_bar_alarm_clock))
+    }
+
     private fun stubViews() {
         `when`(view.findViewById<View>(anyInt())).thenReturn(mockView)
         `when`(view.findViewById<QSCarrierGroup>(R.id.carrier_group)).thenReturn(qsCarrierGroup)
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/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
index 23e5168..2c76be6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -97,7 +97,7 @@
         ImageView iv = mock(ImageView.class);
         State s = new State();
         s.state = Tile.STATE_ACTIVE;
-        int desiredColor = mIconView.getColor(s.state);
+        int desiredColor = mIconView.getColor(s);
         when(iv.isShown()).thenReturn(true);
 
         mIconView.setIcon(iv, s, true);
@@ -109,7 +109,7 @@
         ImageView iv = mock(ImageView.class);
         State s = new State();
         s.state = Tile.STATE_ACTIVE;
-        int desiredColor = mIconView.getColor(s.state);
+        int desiredColor = mIconView.getColor(s);
         Icon i = mock(Icon.class);
         s.icon = i;
         when(i.toString()).thenReturn("MOCK ICON");
@@ -124,6 +124,18 @@
         assertFalse(mIconView.toString().contains("lastIcon"));
     }
 
+    @Test
+    public void testIconColorDisabledByPolicy_sameAsUnavailable() {
+        State s1 = new State();
+        s1.state = Tile.STATE_INACTIVE;
+        s1.disabledByPolicy = true;
+
+        State s2 = new State();
+        s2.state = Tile.STATE_UNAVAILABLE;
+
+        assertEquals(mIconView.getColor(s1), mIconView.getColor(s2));
+    }
+
     private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) {
         return new Drawable.ConstantState() {
             @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
index 9fdc2fd..d3ec1dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileViewImplTest.kt
@@ -280,6 +280,88 @@
         assertThat(info.collectionItemInfo).isNull()
     }
 
+    @Test
+    fun testDisabledByPolicyInactive_usesUnavailableColors() {
+        val stateDisabledByPolicy = QSTile.State()
+        stateDisabledByPolicy.state = Tile.STATE_INACTIVE
+        stateDisabledByPolicy.disabledByPolicy = true
+
+        val stateUnavailable = QSTile.State()
+        stateUnavailable.state = Tile.STATE_UNAVAILABLE
+
+        tileView.changeState(stateDisabledByPolicy)
+        val colorsDisabledByPolicy = tileView.getCurrentColors()
+
+        tileView.changeState(stateUnavailable)
+        val colorsUnavailable = tileView.getCurrentColors()
+
+        assertThat(colorsDisabledByPolicy).containsExactlyElementsIn(colorsUnavailable)
+    }
+
+    @Test
+    fun testDisabledByPolicyActive_usesUnavailableColors() {
+        val stateDisabledByPolicy = QSTile.State()
+        stateDisabledByPolicy.state = Tile.STATE_ACTIVE
+        stateDisabledByPolicy.disabledByPolicy = true
+
+        val stateUnavailable = QSTile.State()
+        stateUnavailable.state = Tile.STATE_UNAVAILABLE
+
+        tileView.changeState(stateDisabledByPolicy)
+        val colorsDisabledByPolicy = tileView.getCurrentColors()
+
+        tileView.changeState(stateUnavailable)
+        val colorsUnavailable = tileView.getCurrentColors()
+
+        assertThat(colorsDisabledByPolicy).containsExactlyElementsIn(colorsUnavailable)
+    }
+
+    @Test
+    fun testDisabledByPolicy_secondaryLabelText() {
+        val testA11yLabel = "TEST_LABEL"
+        context.orCreateTestableResources
+                .addOverride(
+                        R.string.accessibility_tile_disabled_by_policy_action_description,
+                        testA11yLabel
+                )
+
+        val stateDisabledByPolicy = QSTile.State()
+        stateDisabledByPolicy.state = Tile.STATE_INACTIVE
+        stateDisabledByPolicy.disabledByPolicy = true
+
+        tileView.changeState(stateDisabledByPolicy)
+
+        val info = AccessibilityNodeInfo(tileView)
+        tileView.onInitializeAccessibilityNodeInfo(info)
+        assertThat(
+                info.actionList.find {
+                        it.id == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id
+                }?.label
+        ).isEqualTo(testA11yLabel)
+    }
+
+    @Test
+    fun testDisabledByPolicy_unavailableInStateDescription() {
+        val state = QSTile.BooleanState()
+        val spec = "internet"
+        state.spec = spec
+        state.disabledByPolicy = true
+        state.state = Tile.STATE_INACTIVE
+
+        val unavailableString = "${spec}_unavailable"
+        val offString = "${spec}_off"
+        val onString = "${spec}_on"
+
+        context.orCreateTestableResources.addOverride(R.array.tile_states_internet, arrayOf(
+                unavailableString,
+                offString,
+                onString
+        ))
+
+        tileView.changeState(state)
+        assertThat(tileView.stateDescription?.contains(unavailableString)).isTrue()
+    }
+
     class FakeTileView(
         context: Context,
         icon: QSIconView,
@@ -289,4 +371,4 @@
             handleStateChanged(state)
         }
     }
-}
\ No newline at end of file
+}
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/UserDetailViewAdapterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/UserDetailViewAdapterTest.kt
index 9b0142d..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
@@ -31,6 +31,7 @@
 import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.qs.QSUserSwitcherEvent
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.source.UserRecord
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
@@ -39,8 +40,8 @@
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
@@ -52,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
@@ -140,13 +140,14 @@
     }
 
     private fun createUserRecord(current: Boolean, guest: Boolean) =
-            UserSwitcherController.UserRecord(
-                    mUserInfo,
-                    mPicture,
-                    guest,
-                    current,
-                    false /* isAddUser */,
-                    false /* isRestricted */,
-                    true /* isSwitchToEnabled */,
-                    false /* isAddSupervisedUser */)
+        UserRecord(
+            UserInfo(0 /* id */, "name", 0 /* flags */),
+            mPicture,
+            guest,
+            current,
+            false /* isAddUser */,
+            false /* isRestricted */,
+            true /* isSwitchToEnabled */,
+            false /* isAddSupervisedUser */
+        )
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
index 48fbd35..073c23c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -23,6 +23,7 @@
 import android.graphics.Rect
 import android.hardware.HardwareBuffer
 import android.os.Bundle
+import android.os.UserHandle
 import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
 import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
 import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
@@ -97,7 +98,7 @@
         policy.setManagedProfile(USER_ID, false)
         policy.setDisplayContentInfo(
             policy.getDefaultDisplayId(),
-            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
 
         val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
         val processor = RequestProcessor(imageCapture, policy, flags, scope)
@@ -120,7 +121,7 @@
         // Indicate that the primary content belongs to a manged profile
         policy.setManagedProfile(USER_ID, true)
         policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
-            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
 
         val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
         val processor = RequestProcessor(imageCapture, policy, flags, scope)
@@ -160,7 +161,7 @@
 
         policy.setManagedProfile(USER_ID, false)
         policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
-            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
 
         val processedRequest = processor.process(request)
 
@@ -183,7 +184,7 @@
         // Indicate that the primary content belongs to a manged profile
         policy.setManagedProfile(USER_ID, true)
         policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
-            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
+            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
 
         val processedRequest = processor.process(request)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
new file mode 100644
index 0000000..17396b1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.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.systemui.screenshot
+
+import android.app.ActivityTaskManager.RootTaskInfo
+import android.app.IActivityTaskManager
+import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
+import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
+import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED
+import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
+import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.Rect
+import android.os.UserHandle
+import android.os.UserManager
+import android.testing.AndroidTestingRunner
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
+import com.android.systemui.util.mockito.mock
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+// The following values are chosen to be distinct from commonly seen real values
+private const val DISPLAY_ID = 100
+private const val PRIMARY_USER = 2000
+private const val MANAGED_PROFILE_USER = 3000
+
+@RunWith(AndroidTestingRunner::class)
+class ScreenshotPolicyImplTest : SysuiTestCase() {
+
+    @Test
+    fun testToDisplayContentInfo() {
+        assertThat(fullScreenWorkProfileTask.toDisplayContentInfo())
+            .isEqualTo(
+                DisplayContentInfo(
+                    ComponentName(
+                        "com.google.android.apps.nbu.files",
+                        "com.google.android.apps.nbu.files.home.HomeActivity"
+                    ),
+                    Rect(0, 0, 1080, 2400),
+                    UserHandle.of(MANAGED_PROFILE_USER),
+                    65))
+    }
+
+    @Test
+    fun findPrimaryContent_ignoresPipTask() = runBlocking {
+        val policy = fakeTasksPolicyImpl(
+            mContext,
+            shadeExpanded = false,
+            tasks = listOf(
+                    pipTask,
+                    fullScreenWorkProfileTask,
+                    launcherTask,
+                    emptyTask)
+        )
+
+        val info = policy.findPrimaryContent(DISPLAY_ID)
+        assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo())
+    }
+
+    @Test
+    fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking {
+        val policy = fakeTasksPolicyImpl(
+            mContext,
+            shadeExpanded = true,
+            tasks = listOf(
+                fullScreenWorkProfileTask,
+                launcherTask,
+                emptyTask)
+        )
+
+        val info = policy.findPrimaryContent(DISPLAY_ID)
+        assertThat(info).isEqualTo(policy.systemUiContent)
+    }
+
+    @Test
+    fun findPrimaryContent_emptyTaskList() = runBlocking {
+        val policy = fakeTasksPolicyImpl(
+            mContext,
+            shadeExpanded = false,
+            tasks = listOf()
+        )
+
+        val info = policy.findPrimaryContent(DISPLAY_ID)
+        assertThat(info).isEqualTo(policy.systemUiContent)
+    }
+
+    @Test
+    fun findPrimaryContent_workProfileNotOnTop() = runBlocking {
+        val policy = fakeTasksPolicyImpl(
+            mContext,
+            shadeExpanded = false,
+            tasks = listOf(
+                launcherTask,
+                fullScreenWorkProfileTask,
+                emptyTask)
+        )
+
+        val info = policy.findPrimaryContent(DISPLAY_ID)
+        assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo())
+    }
+
+    private fun fakeTasksPolicyImpl(
+        context: Context,
+        shadeExpanded: Boolean,
+        tasks: List<RootTaskInfo>
+    ): ScreenshotPolicyImpl {
+        val userManager = mock<UserManager>()
+        val atmService = mock<IActivityTaskManager>()
+        val dispatcher = Dispatchers.Unconfined
+
+        return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher) {
+            override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER)
+            override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks
+            override suspend fun isNotificationShadeExpanded() = shadeExpanded
+        }
+    }
+
+    private val pipTask = RootTaskInfo().apply {
+        configuration.windowConfiguration.apply {
+            windowingMode = WINDOWING_MODE_PINNED
+            bounds = Rect(628, 1885, 1038, 2295)
+            activityType = ACTIVITY_TYPE_STANDARD
+        }
+        displayId = DISPLAY_ID
+        userId = PRIMARY_USER
+        taskId = 66
+        visible = true
+        isVisible = true
+        isRunning = true
+        numActivities = 1
+        topActivity = ComponentName(
+            "com.google.android.youtube",
+            "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity"
+        )
+        childTaskIds = intArrayOf(66)
+        childTaskNames = arrayOf("com.google.android.youtube/" +
+                "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity")
+        childTaskUserIds = intArrayOf(0)
+        childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295))
+    }
+
+    private val fullScreenWorkProfileTask = RootTaskInfo().apply {
+        configuration.windowConfiguration.apply {
+            windowingMode = WINDOWING_MODE_FULLSCREEN
+            bounds = Rect(0, 0, 1080, 2400)
+            activityType = ACTIVITY_TYPE_STANDARD
+        }
+        displayId = DISPLAY_ID
+        userId = MANAGED_PROFILE_USER
+        taskId = 65
+        visible = true
+        isVisible = true
+        isRunning = true
+        numActivities = 1
+        topActivity = ComponentName(
+            "com.google.android.apps.nbu.files",
+            "com.google.android.apps.nbu.files.home.HomeActivity"
+        )
+        childTaskIds = intArrayOf(65)
+        childTaskNames = arrayOf("com.google.android.apps.nbu.files/" +
+                "com.google.android.apps.nbu.files.home.HomeActivity")
+        childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER)
+        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400))
+    }
+
+    private val launcherTask = RootTaskInfo().apply {
+        configuration.windowConfiguration.apply {
+            windowingMode = WINDOWING_MODE_FULLSCREEN
+            bounds = Rect(0, 0, 1080, 2400)
+            activityType = ACTIVITY_TYPE_HOME
+        }
+        displayId = DISPLAY_ID
+        taskId = 1
+        userId = PRIMARY_USER
+        visible = true
+        isVisible = true
+        isRunning = true
+        numActivities = 1
+        topActivity = ComponentName(
+            "com.google.android.apps.nexuslauncher",
+            "com.google.android.apps.nexuslauncher.NexusLauncherActivity",
+        )
+        childTaskIds = intArrayOf(1)
+        childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" +
+                "com.google.android.apps.nexuslauncher.NexusLauncherActivity")
+        childTaskUserIds = intArrayOf(0)
+        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400))
+    }
+
+    private val emptyTask = RootTaskInfo().apply {
+        configuration.windowConfiguration.apply {
+            windowingMode = WINDOWING_MODE_FULLSCREEN
+            bounds = Rect(0, 0, 1080, 2400)
+            activityType = ACTIVITY_TYPE_UNDEFINED
+        }
+        displayId = DISPLAY_ID
+        taskId = 2
+        userId = PRIMARY_USER
+        visible = false
+        isVisible = false
+        isRunning = false
+        numActivities = 0
+        childTaskIds = intArrayOf(3, 4)
+        childTaskNames = arrayOf("", "")
+        childTaskUserIds = intArrayOf(0, 0)
+        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
index 83e56da..6ce9cff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags.SCREENSHOT_REQUEST_PROCESSOR
+import com.android.systemui.flags.Flags.SCREENSHOT_WORK_PROFILE_POLICY
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_KEY_CHORD
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_REQUESTED_OVERVIEW
 import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback
@@ -47,12 +48,15 @@
 import com.android.systemui.util.mockito.argThat
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
+import java.util.function.Consumer
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.isNull
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.Mockito.`when` as whenever
@@ -88,7 +92,16 @@
             .thenReturn(false)
         whenever(userManager.isUserUnlocked).thenReturn(true)
 
+        // Stub request processor as a synchronous no-op for tests with the flag enabled
+        doAnswer {
+            val request: ScreenshotRequest = it.getArgument(0) as ScreenshotRequest
+            val consumer: Consumer<ScreenshotRequest> = it.getArgument(1)
+            consumer.accept(request)
+        }.`when`(requestProcessor).processAsync(/* request= */ any(), /* callback= */ any())
+
+        // Flipped in selected test cases
         flags.set(SCREENSHOT_REQUEST_PROCESSOR, false)
+        flags.set(SCREENSHOT_WORK_PROFILE_POLICY, false)
 
         service.attach(
             mContext,
@@ -105,10 +118,10 @@
         service.onBind(null /* unused: Intent */)
 
         service.onUnbind(null /* unused: Intent */)
-        verify(controller).removeWindow()
+        verify(controller, times(1)).removeWindow()
 
         service.onDestroy()
-        verify(controller).onDestroy()
+        verify(controller, times(1)).onDestroy()
     }
 
     @Test
@@ -120,7 +133,32 @@
 
         service.handleRequest(request, { /* onSaved */ }, callback)
 
-        verify(controller).takeScreenshotFullscreen(
+        verify(controller, times(1)).takeScreenshotFullscreen(
+            eq(topComponent),
+            /* onSavedListener = */ any(),
+            /* requestCallback = */ any())
+
+        assertEquals("Expected one UiEvent", eventLogger.numLogs(), 1)
+        val logEvent = eventLogger.get(0)
+
+        assertEquals("Expected SCREENSHOT_REQUESTED UiEvent",
+            logEvent.eventId, SCREENSHOT_REQUESTED_KEY_CHORD.id)
+        assertEquals("Expected supplied package name",
+            topComponent.packageName, eventLogger.get(0).packageName)
+    }
+
+    @Test
+    fun takeScreenshot_requestProcessorEnabled() {
+        flags.set(SCREENSHOT_REQUEST_PROCESSOR, true)
+
+        val request = ScreenshotRequest(
+            TAKE_SCREENSHOT_FULLSCREEN,
+            SCREENSHOT_KEY_CHORD,
+            topComponent)
+
+        service.handleRequest(request, { /* onSaved */ }, callback)
+
+        verify(controller, times(1)).takeScreenshotFullscreen(
             eq(topComponent),
             /* onSavedListener = */ any(),
             /* requestCallback = */ any())
@@ -143,7 +181,7 @@
 
         service.handleRequest(request, { /* onSaved */ }, callback)
 
-        verify(controller).takeScreenshotPartial(
+        verify(controller, times(1)).takeScreenshotPartial(
             /* topComponent = */ isNull(),
             /* onSavedListener = */ any(),
             /* requestCallback = */ any())
@@ -167,7 +205,7 @@
 
         service.handleRequest(request, { /* onSaved */ }, callback)
 
-        verify(controller).handleImageAsScreenshot(
+        verify(controller, times(1)).handleImageAsScreenshot(
             argThat { b -> b.equalsHardwareBitmap(bitmap) },
             eq(bounds),
             eq(Insets.NONE), eq(TASK_ID), eq(USER_ID), eq(topComponent),
@@ -193,8 +231,8 @@
 
         service.handleRequest(request, { /* onSaved */ }, callback)
 
-        verify(notificationsController).notifyScreenshotError(anyInt())
-        verify(callback).reportError()
+        verify(notificationsController, times(1)).notifyScreenshotError(anyInt())
+        verify(callback, times(1)).reportError()
         verifyZeroInteractions(controller)
     }
 
@@ -217,7 +255,7 @@
         service.handleRequest(request, { /* onSaved */ }, callback)
 
         // error shown: Toast.makeText(...).show(), untestable
-        verify(callback).reportError()
+        verify(callback, times(1)).reportError()
         verifyZeroInteractions(controller)
     }
 }
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 20c6d9a..e85ffb6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -607,6 +607,13 @@
         verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
     }
 
+    @Test
+    fun alarmIconNotIgnored() {
+        verify(statusIcons, never()).addIgnoredSlot(
+                context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+        )
+    }
+
     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 eeb61bc..8511443 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -191,4 +191,11 @@
         verify(date).setTextAppearance(R.style.TextAppearance_QS_Status)
         verify(carrierGroup).updateTextAppearance(R.style.TextAppearance_QS_Status_Carriers)
     }
+
+    @Test
+    fun alarmIconIgnored() {
+        verify(statusIcons).addIgnoredSlot(
+                context.getString(com.android.internal.R.string.status_bar_alarm_clock)
+        )
+    }
 }
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 98389c2..f1c54ef 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;
@@ -124,7 +125,6 @@
 import com.android.systemui.statusbar.events.PrivacyDotViewController;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
@@ -161,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;
@@ -186,227 +184,134 @@
 public class NotificationPanelViewControllerTest extends SysuiTestCase {
 
     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 NotificationEntryManager mNotificationEntryManager;
-    @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);
@@ -434,7 +339,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);
@@ -450,7 +355,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;
@@ -458,7 +368,6 @@
 
         NotificationWakeUpCoordinator coordinator =
                 new NotificationWakeUpCoordinator(
-                        mDumpManager,
                         mock(HeadsUpManagerPhone.class),
                         new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
                                 mInteractionJankMonitor),
@@ -488,7 +397,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()))
@@ -503,13 +412,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,
@@ -518,7 +432,6 @@
                 mFeatureFlags,
                 coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
                 mFalsingManager, new FalsingCollectorFake(),
-                mNotificationEntryManager,
                 mKeyguardStateController,
                 mStatusBarStateController,
                 mStatusBarWindowStateController,
@@ -552,8 +465,6 @@
                 mNavigationModeController,
                 mFragmentService,
                 mContentResolver,
-                mQuickAccessWalletController,
-                mQrCodeScannerController,
                 mRecordingController,
                 mLargeScreenShadeHeaderController,
                 mScreenOffAnimationController,
@@ -561,21 +472,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,
                 () -> {},
@@ -1489,6 +1399,96 @@
         assertThat(maxPanelHeight).isNotEqualTo(splitShadeFullTransitionDistance);
     }
 
+    @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) {
         return MotionEvent.obtain(
                 /* downTime= */ 0, /* eventTime= */ 0, action, x, y, /* metaState= */ 0);
@@ -1512,12 +1512,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);
@@ -1574,4 +1568,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/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 6d059b1..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,13 +19,14 @@
 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
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
-import com.android.systemui.lowlightclock.LowLightClockController
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
 import com.android.systemui.statusbar.NotificationShadeDepthController
@@ -39,12 +40,10 @@
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
 import com.google.common.truth.Truth.assertThat
-import java.util.Optional
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
-import org.mockito.ArgumentMatchers
 import org.mockito.Mock
 import org.mockito.Mockito.anyFloat
 import org.mockito.Mockito.never
@@ -87,8 +86,6 @@
     @Mock
     private lateinit var phoneStatusBarViewController: PhoneStatusBarViewController
     @Mock
-    private lateinit var lowLightClockController: LowLightClockController
-    @Mock
     private lateinit var pulsingGestureListener: PulsingGestureListener
 
     private lateinit var interactionEventHandlerCaptor: ArgumentCaptor<InteractionEventHandler>
@@ -114,7 +111,6 @@
             statusBarKeyguardViewManager,
             statusBarWindowStateController,
             lockIconViewController,
-            Optional.of(lowLightClockController),
             centralSurfaces,
             notificationShadeWindowController,
             keyguardUnlockAnimationController,
@@ -254,28 +250,15 @@
     }
 
     @Test
-    fun testLowLightClockAttachedWhenExpandedStatusBarSetup() {
-        verify(lowLightClockController).attachLowLightClockView(ArgumentMatchers.any())
+    fun testGetBouncerContainer() {
+        underTest.bouncerContainer
+        verify(view).findViewById<ViewGroup>(R.id.keyguard_bouncer_container)
     }
 
     @Test
-    fun testLowLightClockShownWhenDozing() {
-        underTest.setDozing(true)
-        verify(lowLightClockController).showLowLightClock(true)
-    }
-
-    @Test
-    fun testLowLightClockDozeTimeTickCalled() {
-        underTest.dozeTimeTick()
-        verify(lowLightClockController).dozeTimeTick()
-    }
-
-    @Test
-    fun testLowLightClockHiddenWhenNotDozing() {
-        underTest.setDozing(true)
-        verify(lowLightClockController).showLowLightClock(true)
-        underTest.setDozing(false)
-        verify(lowLightClockController).showLowLightClock(false)
+    fun testGetKeyguardMessageArea() {
+        underTest.keyguardMessageArea
+        verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
index 89a2518..001bfee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.java
@@ -38,7 +38,6 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.lowlightclock.LowLightClockController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
@@ -61,8 +60,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.Optional;
-
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 @SmallTest
@@ -86,7 +83,6 @@
     @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
     @Mock private LockIconViewController mLockIconViewController;
-    @Mock private LowLightClockController mLowLightClockController;
     @Mock private KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     @Mock private AmbientState mAmbientState;
     @Mock private PulsingGestureListener mPulsingGestureListener;
@@ -121,7 +117,6 @@
                 mStatusBarKeyguardViewManager,
                 mStatusBarWindowStateController,
                 mLockIconViewController,
-                Optional.of(mLowLightClockController),
                 mCentralSurfaces,
                 mNotificationShadeWindowController,
                 mKeyguardUnlockAnimationController,
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/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 7869448..2b4a109 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -19,17 +19,31 @@
 import android.content.res.Resources
 import android.graphics.drawable.Drawable
 import android.testing.AndroidTestingRunner
+import android.util.TypedValue
 import android.view.LayoutInflater
+import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.shared.clocks.DefaultClock.Companion.DOZE_COLOR
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import java.util.Locale
+import java.util.TimeZone
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertNotNull
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.notNull
 import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
 
@@ -39,7 +53,8 @@
 
     @JvmField @Rule val mockito = MockitoJUnit.rule()
 
-    @Mock private lateinit var mockClockView: AnimatableClockView
+    @Mock private lateinit var mockSmallClockView: AnimatableClockView
+    @Mock private lateinit var mockLargeClockView: AnimatableClockView
     @Mock private lateinit var layoutInflater: LayoutInflater
     @Mock private lateinit var mockClockThumbnail: Drawable
     @Mock private lateinit var resources: Resources
@@ -47,14 +62,16 @@
 
     @Before
     fun setUp() {
-        whenever(layoutInflater.inflate(R.layout.clock_default_small, null))
-            .thenReturn(mockClockView)
-        whenever(layoutInflater.inflate(R.layout.clock_default_large, null))
-            .thenReturn(mockClockView)
+        whenever(layoutInflater.inflate(eq(R.layout.clock_default_small), any(), anyBoolean()))
+            .thenReturn(mockSmallClockView)
+        whenever(layoutInflater.inflate(eq(R.layout.clock_default_large), any(), anyBoolean()))
+            .thenReturn(mockLargeClockView)
         whenever(resources.getDrawable(R.drawable.clock_default_thumbnail, null))
             .thenReturn(mockClockThumbnail)
+        whenever(mockSmallClockView.getLayoutParams()).thenReturn(FrameLayout.LayoutParams(10, 10))
+        whenever(mockLargeClockView.getLayoutParams()).thenReturn(FrameLayout.LayoutParams(10, 10))
 
-        provider = DefaultClockProvider(layoutInflater, resources)
+        provider = DefaultClockProvider(context, layoutInflater, resources)
     }
 
     @Test
@@ -71,7 +88,79 @@
         // Default clock provider must always provide the default clock
         val clock = provider.createClock(DEFAULT_CLOCK_ID)
         assertNotNull(clock)
-        assertEquals(clock.smallClock, mockClockView)
-        assertEquals(clock.largeClock, mockClockView)
+        assertEquals(clock.smallClock, mockSmallClockView)
+        assertEquals(clock.largeClock, mockLargeClockView)
+    }
+
+    @Test
+    fun defaultClock_initialize() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.initialize(resources, 0f, 0f)
+
+        verify(mockSmallClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt())
+        verify(mockLargeClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt())
+        verify(mockSmallClockView).onTimeZoneChanged(notNull())
+        verify(mockLargeClockView).onTimeZoneChanged(notNull())
+        verify(mockSmallClockView).refreshTime()
+        verify(mockLargeClockView).refreshTime()
+        verify(mockLargeClockView).setLayoutParams(any())
+    }
+
+    @Test
+    fun defaultClock_events_onTimeTick() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.events.onTimeTick()
+
+        verify(mockSmallClockView).refreshTime()
+        verify(mockLargeClockView).refreshTime()
+    }
+
+    @Test
+    fun defaultClock_events_onTimeFormatChanged() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.events.onTimeFormatChanged(true)
+
+        verify(mockSmallClockView).refreshFormat(true)
+        verify(mockLargeClockView).refreshFormat(true)
+    }
+
+    @Test
+    fun defaultClock_events_onTimeZoneChanged() {
+        val timeZone = mock<TimeZone>()
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.events.onTimeZoneChanged(timeZone)
+
+        verify(mockSmallClockView).onTimeZoneChanged(timeZone)
+        verify(mockLargeClockView).onTimeZoneChanged(timeZone)
+    }
+
+    @Test
+    fun defaultClock_events_onFontSettingChanged() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.events.onFontSettingChanged()
+
+        verify(mockSmallClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), anyFloat())
+        verify(mockLargeClockView).setTextSize(eq(TypedValue.COMPLEX_UNIT_PX), anyFloat())
+        verify(mockLargeClockView).setLayoutParams(any())
+    }
+
+    @Test
+    fun defaultClock_events_onColorPaletteChanged() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.events.onColorPaletteChanged(resources, true, true)
+
+        verify(mockSmallClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt())
+        verify(mockLargeClockView, times(2)).setColors(eq(DOZE_COLOR), anyInt())
+    }
+
+    @Test
+    fun defaultClock_events_onLocaleChanged() {
+        val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        clock.events.onLocaleChanged(Locale.getDefault())
+
+        verify(mockSmallClockView, times(2)).setLineSpacingScale(anyFloat())
+        verify(mockLargeClockView, times(2)).setLineSpacingScale(anyFloat())
+        verify(mockSmallClockView, times(2)).refreshFormat()
+        verify(mockLargeClockView, times(2)).refreshFormat()
     }
 }
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
[email protected]
+@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 351dd0c..74e2747 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -19,6 +19,7 @@
 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_ERROR_TIMEOUT;
 
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -65,7 +66,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;
@@ -570,12 +570,39 @@
     }
 
     @Test
+    public void onBiometricHelp_coEx_faceFailure() {
+        createController();
+
+        // GIVEN unlocking with fingerprint is possible
+        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(anyInt()))
+                .thenReturn(true);
+
+        String message = "A message";
+        mController.setVisible(true);
+
+        // WHEN there's a face not recognized message
+        mController.getKeyguardCallback().onBiometricHelp(
+                KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
+                message,
+                BiometricSourceType.FACE);
+
+        // THEN show sequential messages such as: 'face not recognized' and
+        // 'try fingerprint instead'
+        verifyIndicationMessage(
+                INDICATION_TYPE_BIOMETRIC_MESSAGE,
+                mContext.getString(R.string.keyguard_face_failed));
+        verifyIndicationMessage(
+                INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+                mContext.getString(R.string.keyguard_suggest_fingerprint));
+    }
+
+    @Test
     public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromError() {
         createController();
         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);
@@ -609,10 +636,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
@@ -624,7 +651,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);
     }
 
@@ -671,8 +698,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(
@@ -701,8 +727,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;
@@ -716,6 +741,64 @@
     }
 
     @Test
+    public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() {
+        createController();
+
+        // GIVEN fingerprint NOT enrolled
+        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+                0)).thenReturn(false);
+
+        // WHEN help message received
+        final String helpString = "helpMsg";
+        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
+        final String helpString = "helpMsg";
+        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";
@@ -970,14 +1053,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);
 
@@ -988,6 +1071,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);
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/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 79b1bb0..eb4cca8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -27,12 +27,9 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationEntryListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener;
-import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 
 import org.junit.Before;
@@ -53,10 +50,8 @@
 public class NonPhoneDependencyTest extends SysuiTestCase {
     @Mock private NotificationPresenter mPresenter;
     @Mock private NotificationListContainer mListContainer;
-    @Mock private NotificationEntryListener mEntryListener;
     @Mock private RemoteInputController.Delegate mDelegate;
     @Mock private NotificationRemoteInputManager.Callback mRemoteInputManagerCallback;
-    @Mock private CheckSaveListener mCheckSaveListener;
     @Mock private OnSettingsClickListener mOnSettingsClickListener;
 
     @Before
@@ -70,7 +65,6 @@
     @Ignore("Causes binder calls which fail")
     @Test
     public void testNotificationManagementCodeHasNoDependencyOnStatusBarWindowManager() {
-        NotificationEntryManager entryManager = Dependency.get(NotificationEntryManager.class);
         NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class);
         NotificationLogger notificationLogger = Dependency.get(NotificationLogger.class);
         NotificationMediaManager mediaManager = Dependency.get(NotificationMediaManager.class);
@@ -78,7 +72,6 @@
                 Dependency.get(NotificationRemoteInputManager.class);
         NotificationLockscreenUserManager lockscreenUserManager =
                 Dependency.get(NotificationLockscreenUserManager.class);
-        entryManager.addNotificationEntryListener(mEntryListener);
         gutsManager.setUpWithPresenter(mPresenter, mListContainer,
                 mOnSettingsClickListener);
         notificationLogger.setUpWithContainer(mListContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index dd2b667..853d1df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,19 +16,11 @@
 
 package com.android.systemui.statusbar;
 
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.content.Intent.ACTION_USER_SWITCHED;
 
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_MEDIA_CONTROLS;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_SILENT;
-
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -60,9 +52,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager.KeyguardNotificationSuppressor;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.NotificationStateChangedListener;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
@@ -92,8 +82,6 @@
     @Mock
     private NotificationVisibilityProvider mVisibilityProvider;
     @Mock
-    private NotificationEntryManager mEntryManager;
-    @Mock
     private CommonNotifCollection mNotifCollection;
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
@@ -122,7 +110,6 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
 
         int currentUserId = ActivityManager.getCurrentUser();
         mSettings = new FakeSettings();
@@ -157,12 +144,6 @@
     }
 
     @Test
-    public void testLockScreenShowNotificationsChangeUpdatesNotifications() {
-        mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
-        verify(mEntryManager, times(1)).updateNotifications(anyString());
-    }
-
-    @Test
     public void testLockScreenShowNotificationsFalse() {
         mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
         mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
@@ -305,13 +286,6 @@
     }
 
     @Test
-    public void testSettingsObserverUpdatesNotifications() {
-        when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
-        mLockscreenUserManager.getSettingsObserverForTest().onChange(false);
-        verify(mEntryManager, times(1)).updateNotifications(anyString());
-    }
-
-    @Test
     public void testActionUserSwitchedCallsOnUserSwitched() {
         Intent intent = new Intent()
                 .setAction(ACTION_USER_SWITCHED)
@@ -359,93 +333,6 @@
         verify(listener, never()).onNotificationStateChanged();
     }
 
-    @Test
-    public void testShowSilentNotifications_settingSaysShow() {
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
-        mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_LOW)
-                .build();
-        entry.setBucket(BUCKET_SILENT);
-
-        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
-    }
-
-    @Test
-    public void testShowSilentNotifications_settingSaysHide() {
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
-        mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
-
-        final Notification notification = mock(Notification.class);
-        when(notification.isForegroundService()).thenReturn(true);
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_LOW)
-                .setNotification(notification)
-                .build();
-        entry.setBucket(BUCKET_SILENT);
-        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
-    }
-
-    @Test
-    public void testShowSilentNotificationsPeopleBucket_settingSaysHide() {
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
-        mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
-
-        final Notification notification = mock(Notification.class);
-        when(notification.isForegroundService()).thenReturn(true);
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_LOW)
-                .setNotification(notification)
-                .build();
-        entry.setBucket(BUCKET_PEOPLE);
-        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
-    }
-
-    @Test
-    public void testShowSilentNotificationsMediaBucket_settingSaysHide() {
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
-        mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
-
-        final Notification notification = mock(Notification.class);
-        when(notification.isForegroundService()).thenReturn(true);
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_LOW)
-                .setNotification(notification)
-                .build();
-        entry.setBucket(BUCKET_MEDIA_CONTROLS);
-        // always show media controls, even if they're silent
-        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
-    }
-
-    @Test
-    public void testKeyguardNotificationSuppressors() {
-        // GIVEN a notification that should be shown on the lockscreen
-        mSettings.putInt(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
-        mLockscreenUserManager.getLockscreenSettingsObserverForTest().onChange(false);
-        final NotificationEntry entry = new NotificationEntryBuilder()
-                .setImportance(IMPORTANCE_HIGH)
-                .build();
-        entry.setBucket(BUCKET_ALERTING);
-
-        // WHEN a suppressor is added that filters out all entries
-        FakeKeyguardSuppressor suppressor = new FakeKeyguardSuppressor();
-        mLockscreenUserManager.addKeyguardNotificationSuppressor(suppressor);
-
-        // THEN it's filtered out
-        assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
-
-        // WHEN the suppressor no longer filters out entries
-        suppressor.setShouldSuppress(false);
-
-        // THEN it's no longer filtered out
-        assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
-    }
-
     private class TestNotificationLockscreenUserManager
             extends NotificationLockscreenUserManagerImpl {
         public TestNotificationLockscreenUserManager(Context context) {
@@ -478,17 +365,4 @@
             return mSettingsObserver;
         }
     }
-
-    private static class FakeKeyguardSuppressor implements KeyguardNotificationSuppressor {
-        private boolean mShouldSuppress = true;
-
-        @Override
-        public boolean shouldSuppressOnKeyguard(NotificationEntry entry) {
-            return mShouldSuppress;
-        }
-
-        public void setShouldSuppress(boolean shouldSuppress) {
-            mShouldSuppress = shouldSuppress;
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index 6e29669..5170678 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -23,8 +23,6 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
@@ -36,7 +34,6 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -70,7 +67,6 @@
     @Mock private StatusBarStateController mStateController;
     @Mock private RemoteInputUriController mRemoteInputUriController;
     @Mock private NotificationClickNotifier mClickNotifier;
-    @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
 
     private TestableNotificationRemoteInputManager mRemoteInputManager;
@@ -85,11 +81,8 @@
                 mLockscreenUserManager,
                 mSmartReplyController,
                 mVisibilityProvider,
-                mEntryManager,
-                mock(RemoteInputNotificationRebuilder.class),
                 () -> Optional.of(mock(CentralSurfaces.class)),
                 mStateController,
-                Handler.createAsync(Looper.myLooper()),
                 mRemoteInputUriController,
                 mClickNotifier,
                 mock(ActionClickLogger.class),
@@ -145,11 +138,8 @@
                 NotificationLockscreenUserManager lockscreenUserManager,
                 SmartReplyController smartReplyController,
                 NotificationVisibilityProvider visibilityProvider,
-                NotificationEntryManager notificationEntryManager,
-                RemoteInputNotificationRebuilder rebuilder,
                 Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
                 StatusBarStateController statusBarStateController,
-                Handler mainHandler,
                 RemoteInputUriController remoteInputUriController,
                 NotificationClickNotifier clickNotifier,
                 ActionClickLogger actionClickLogger,
@@ -160,7 +150,6 @@
                     lockscreenUserManager,
                     smartReplyController,
                     visibilityProvider,
-                    notificationEntryManager,
                     centralSurfacesOptionalLazy,
                     statusBarStateController,
                     remoteInputUriController,
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..6446fb5d 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
[email protected]
+@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/connectivity/ui/MobileContextProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
new file mode 100644
index 0000000..0fdda62
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/connectivity/ui/MobileContextProviderTest.kt
@@ -0,0 +1,122 @@
+/*
+ * 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.connectivity.ui
+
+import android.telephony.SubscriptionInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.connectivity.NetworkController
+import com.android.systemui.statusbar.connectivity.SignalCallback
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MobileContextProviderTest : SysuiTestCase() {
+    @Mock private lateinit var networkController: NetworkController
+    @Mock private lateinit var dumpManager: DumpManager
+    @Mock private lateinit var demoModeController: DemoModeController
+
+    private lateinit var provider: MobileContextProvider
+    private lateinit var signalCallback: SignalCallback
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        provider =
+            MobileContextProvider(
+                networkController,
+                dumpManager,
+                demoModeController,
+            )
+
+        signalCallback = withArgCaptor { verify(networkController).addCallback(capture()) }
+    }
+
+    @Test
+    fun test_oneSubscription_contextHasMccMnc() {
+        // GIVEN there is one SubscriptionInfo
+        signalCallback.setSubs(listOf(SUB_1))
+
+        // WHEN we ask for a mobile context
+        val ctx = provider.getMobileContextForSub(SUB_1_ID, context)
+
+        // THEN the configuration of that context reflect this subscription's MCC/MNC override
+        val config = ctx.resources.configuration
+        assertThat(config.mcc).isEqualTo(SUB_1_MCC)
+        assertThat(config.mnc).isEqualTo(SUB_1_MNC)
+    }
+
+    @Test
+    fun test_twoSubscriptions_eachContextReflectsMccMnc() {
+        // GIVEN there are two SubscriptionInfos
+        signalCallback.setSubs(listOf(SUB_1, SUB_2))
+
+        // WHEN we ask for a mobile context for each sub
+        val ctx1 = provider.getMobileContextForSub(SUB_1_ID, context)
+        val ctx2 = provider.getMobileContextForSub(SUB_2_ID, context)
+
+        // THEN the configuration of each context reflect this subscription's MCC/MNC override
+        val config1 = ctx1.resources.configuration
+        assertThat(config1.mcc).isEqualTo(SUB_1_MCC)
+        assertThat(config1.mnc).isEqualTo(SUB_1_MNC)
+
+        val config2 = ctx2.resources.configuration
+        assertThat(config2.mcc).isEqualTo(SUB_2_MCC)
+        assertThat(config2.mnc).isEqualTo(SUB_2_MNC)
+    }
+
+    @Test
+    fun test_requestingContextForNonexistentSubscription_returnsGivenContext() {
+        // GIVEN no SubscriptionInfos
+        signalCallback.setSubs(listOf())
+
+        // WHEN we ask for a mobile context for an unknown subscription
+        val ctx = provider.getMobileContextForSub(SUB_1_ID, context)
+
+        // THEN we get the original context back
+        assertThat(ctx).isEqualTo(context)
+    }
+
+    private val SUB_1_ID = 1
+    private val SUB_1_MCC = 123
+    private val SUB_1_MNC = 456
+    private val SUB_1 =
+        mock<SubscriptionInfo>().also {
+            whenever(it.subscriptionId).thenReturn(SUB_1_ID)
+            whenever(it.mcc).thenReturn(SUB_1_MCC)
+            whenever(it.mnc).thenReturn(SUB_1_MNC)
+        }
+
+    private val SUB_2_ID = 2
+    private val SUB_2_MCC = 666
+    private val SUB_2_MNC = 777
+    private val SUB_2 =
+        mock<SubscriptionInfo>().also {
+            whenever(it.subscriptionId).thenReturn(SUB_2_ID)
+            whenever(it.mcc).thenReturn(SUB_2_MCC)
+            whenever(it.mnc).thenReturn(SUB_2_MNC)
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
similarity index 98%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
index c0d1155..4b5d0a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/DisableFlagsLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableFlagsLoggerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar
+package com.android.systemui.statusbar.disableflags
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -113,7 +113,7 @@
 
     @Test
     fun getDisableFlagsString_newAfterLocalModificationSameAsNew_localModNotLogged() {
-        val newState =  DisableFlagsLogger.DisableState(
+        val newState = DisableFlagsLogger.DisableState(
                 0b001, // abC
                 0b10 // mn
         )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.kt
new file mode 100644
index 0000000..215afb2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/disableflags/DisableStateTrackerTest.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.statusbar.disableflags
+
+import android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS
+import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
+import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
+import android.app.StatusBarManager.DISABLE_CLOCK
+import android.app.StatusBarManager.DISABLE_EXPAND
+import android.app.StatusBarManager.DISABLE_NAVIGATION
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
+import android.app.StatusBarManager.DISABLE_NOTIFICATION_TICKER
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.CommandQueue
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class DisableStateTrackerTest : SysuiTestCase() {
+
+    private lateinit var underTest: DisableStateTracker
+
+    @Mock private lateinit var commandQueue: CommandQueue
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun startTracking_commandQueueGetsCallback() {
+        underTest = DisableStateTracker(0, 0) { }
+
+        underTest.startTracking(commandQueue, displayId = 0)
+
+        verify(commandQueue).addCallback(underTest)
+    }
+
+    @Test
+    fun stopTracking_commandQueueLosesCallback() {
+        underTest = DisableStateTracker(0, 0) { }
+
+        underTest.stopTracking(commandQueue)
+
+        verify(commandQueue).removeCallback(underTest)
+    }
+
+    @Test
+    fun disable_hadNotStartedTracking_isDisabledFalse() {
+        underTest = DisableStateTracker(DISABLE_CLOCK, 0) { }
+
+        underTest.disable(displayId = 0, state1 = DISABLE_CLOCK, state2 = 0, animate = false)
+
+        assertThat(underTest.isDisabled).isFalse()
+    }
+
+    @Test
+    fun disable_wrongDisplayId_isDisabledFalse() {
+        underTest = DisableStateTracker(DISABLE_CLOCK, 0) { }
+        underTest.startTracking(commandQueue, displayId = 15)
+
+        underTest.disable(displayId = 20, state1 = DISABLE_CLOCK, state2 = 0, animate = false)
+
+        assertThat(underTest.isDisabled).isFalse()
+    }
+
+    @Test
+    fun disable_irrelevantFlagsUpdated_isDisabledFalse() {
+        underTest = DisableStateTracker(DISABLE_CLOCK, DISABLE2_GLOBAL_ACTIONS) { }
+        underTest.startTracking(commandQueue, DISPLAY_ID)
+
+        underTest.disable(
+            DISPLAY_ID, state1 = DISABLE_EXPAND, state2 = DISABLE2_QUICK_SETTINGS, animate = false
+        )
+
+        assertThat(underTest.isDisabled).isFalse()
+    }
+
+    @Test
+    fun disable_partOfMask1True_isDisabledTrue() {
+        underTest = DisableStateTracker(
+            mask1 = DISABLE_CLOCK or DISABLE_EXPAND or DISABLE_NAVIGATION,
+            mask2 = DISABLE2_GLOBAL_ACTIONS
+        ) { }
+        underTest.startTracking(commandQueue, DISPLAY_ID)
+
+        underTest.disable(DISPLAY_ID, state1 = DISABLE_EXPAND, state2 = 0, animate = false)
+
+        assertThat(underTest.isDisabled).isTrue()
+    }
+
+    @Test
+    fun disable_partOfMask2True_isDisabledTrue() {
+        underTest = DisableStateTracker(
+            mask1 = DISABLE_CLOCK,
+            mask2 = DISABLE2_GLOBAL_ACTIONS or DISABLE2_SYSTEM_ICONS
+        ) { }
+        underTest.startTracking(commandQueue, DISPLAY_ID)
+
+        underTest.disable(DISPLAY_ID, state1 = 0, state2 = DISABLE2_SYSTEM_ICONS, animate = false)
+
+        assertThat(underTest.isDisabled).isTrue()
+    }
+
+    @Test
+    fun disable_isDisabledChangesFromFalseToTrue_callbackNotified() {
+        var callbackCalled = false
+
+        underTest = DisableStateTracker(
+            mask1 = DISABLE_CLOCK,
+            mask2 = DISABLE2_GLOBAL_ACTIONS
+        ) { callbackCalled = true }
+        underTest.startTracking(commandQueue, DISPLAY_ID)
+
+        underTest.disable(DISPLAY_ID, state1 = DISABLE_CLOCK, state2 = 0, animate = false)
+
+        assertThat(callbackCalled).isTrue()
+    }
+
+    @Test
+    fun disable_isDisabledChangesFromTrueToFalse_callbackNotified() {
+        var callbackCalled: Boolean
+
+        underTest = DisableStateTracker(
+            mask1 = DISABLE_CLOCK,
+            mask2 = DISABLE2_GLOBAL_ACTIONS
+        ) { callbackCalled = true }
+        underTest.startTracking(commandQueue, DISPLAY_ID)
+
+        // First, update isDisabled to true
+        underTest.disable(DISPLAY_ID, state1 = DISABLE_CLOCK, state2 = 0, animate = false)
+        assertThat(underTest.isDisabled).isTrue()
+
+        // WHEN isDisabled updates back to false
+        callbackCalled = false
+        underTest.disable(DISPLAY_ID, state1 = 0, state2 = 0, animate = false)
+
+        // THEN the callback is called again
+        assertThat(callbackCalled).isTrue()
+    }
+
+    @Test
+    fun disable_manyUpdates_isDisabledUpdatesAppropriately() {
+        underTest = DisableStateTracker(
+            mask1 = DISABLE_CLOCK or DISABLE_EXPAND or DISABLE_NAVIGATION,
+            mask2 = DISABLE2_GLOBAL_ACTIONS or DISABLE2_SYSTEM_ICONS
+        ) { }
+        underTest.startTracking(commandQueue, DISPLAY_ID)
+
+        // All flags from mask1 -> isDisabled = true
+        underTest.disable(
+            DISPLAY_ID,
+            state1 = DISABLE_CLOCK or DISABLE_EXPAND or DISABLE_NAVIGATION,
+            state2 = 0,
+            animate = false
+        )
+        assertThat(underTest.isDisabled).isTrue()
+
+        // Irrelevant flags from mask1 -> isDisabled = false
+        underTest.disable(
+            DISPLAY_ID,
+            state1 = DISABLE_NOTIFICATION_ICONS or DISABLE_NOTIFICATION_TICKER,
+            state2 = 0,
+            animate = false
+        )
+        assertThat(underTest.isDisabled).isFalse()
+
+        // All flags from mask1 & all flags from mask2 -> isDisabled = true
+        underTest.disable(
+            DISPLAY_ID,
+            state1 = DISABLE_CLOCK or DISABLE_EXPAND or DISABLE_NAVIGATION,
+            state2 = DISABLE2_GLOBAL_ACTIONS or DISABLE2_SYSTEM_ICONS,
+            animate = false
+        )
+        assertThat(underTest.isDisabled).isTrue()
+
+        // No flags -> isDisabled = false
+        underTest.disable(DISPLAY_ID, state1 = 0, state2 = 0, animate = false)
+        assertThat(underTest.isDisabled).isFalse()
+
+        // 1 flag from mask1 & 1 flag from mask2 -> isDisabled = true
+        underTest.disable(
+            DISPLAY_ID,
+            state1 = DISABLE_NAVIGATION,
+            state2 = DISABLE2_SYSTEM_ICONS,
+            animate = false
+        )
+        assertThat(underTest.isDisabled).isTrue()
+    }
+
+    companion object {
+        private const val DISPLAY_ID = 3
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
index 3fc0c81..b719c7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/DynamicPrivacyControllerTest.java
@@ -18,7 +18,6 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -128,8 +127,6 @@
     @Test
     public void testNotNotifiedWithoutNotifications() {
         when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true);
-        when(mLockScreenUserManager.shouldHideNotifications(anyInt())).thenReturn(
-                true);
         mDynamicPrivacyController.onUnlockedChanged();
         verifyNoMoreInteractions(mListener);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
deleted file mode 100644
index 19dd027..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification;
-
-import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
-
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.verify;
-
-import android.app.ActivityManager;
-import android.app.Notification;
-import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.R;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-
-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.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
[email protected]
-public class NotificationListControllerTest extends SysuiTestCase {
-    private NotificationListController mController;
-
-    @Mock private NotificationEntryManager mEntryManager;
-    @Mock private NotificationListContainer mListContainer;
-    @Mock private DeviceProvisionedController mDeviceProvisionedController;
-
-    @Captor private ArgumentCaptor<NotificationEntryListener> mEntryListenerCaptor;
-    @Captor private ArgumentCaptor<DeviceProvisionedListener> mProvisionedCaptor;
-
-    private NotificationEntryListener mEntryListener;
-    private DeviceProvisionedListener mProvisionedListener;
-
-    private int mNextNotifId = 0;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
-
-        mController = new NotificationListController(
-                mEntryManager,
-                mListContainer,
-                mDeviceProvisionedController);
-        mController.bind();
-
-        // Capture callbacks passed to mocks
-        verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
-        mEntryListener = mEntryListenerCaptor.getValue();
-        verify(mDeviceProvisionedController).addCallback(mProvisionedCaptor.capture());
-        mProvisionedListener = mProvisionedCaptor.getValue();
-    }
-
-    @Test
-    public void testCleanUpViewStateOnEntryRemoved() {
-        final NotificationEntry entry = buildEntry();
-        mEntryListener.onEntryRemoved(
-                entry,
-                NotificationVisibility.obtain(entry.getKey(), 0, 0, true),
-                false,
-                UNDEFINED_DISMISS_REASON);
-        verify(mListContainer).cleanUpViewStateForEntry(entry);
-    }
-
-    @Test
-    public void testCallUpdateNotificationsOnDeviceProvisionedChange() {
-        mProvisionedListener.onDeviceProvisionedChanged();
-        verify(mEntryManager).updateNotifications(anyString());
-    }
-
-    private NotificationEntry buildEntry() {
-        mNextNotifId++;
-
-        Notification.Builder n = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-
-        return new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setId(mNextNotifId)
-                .setUid(TEST_UID)
-                .setNotification(n.build())
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-    }
-
-    private static final String TEST_PACKAGE_NAME = "test";
-    private static final int TEST_UID = 0;
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
index d4f0505..8272f5a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/SmartspaceDedupingCoordinatorTest.kt
@@ -23,11 +23,9 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceTargetListener
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
-import com.android.systemui.statusbar.notification.NotificationEntryManager
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -46,7 +44,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
-import org.mockito.Mockito.anyString
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
@@ -61,10 +58,6 @@
     @Mock
     private lateinit var smartspaceController: LockscreenSmartspaceController
     @Mock
-    private lateinit var notificationEntryManager: NotificationEntryManager
-    @Mock
-    private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
-    @Mock
     private lateinit var notifPipeline: NotifPipeline
     @Mock
     private lateinit var pluggableListener: Pluggable.PluggableListener<NotifFilter>
@@ -99,12 +92,10 @@
         deduper = SmartspaceDedupingCoordinator(
                 statusBarStateController,
                 smartspaceController,
-                notificationEntryManager,
-                notificationLockscreenUserManager,
                 notifPipeline,
                 executor,
                 clock
-                )
+        )
 
         // Attach the deduper and capture the listeners/filters that it registers
         deduper.attach(notifPipeline)
@@ -352,7 +343,6 @@
         // THEN the new pipeline is invalidated (but the old one isn't because it's not
         // necessary) because the notif should no longer be filtered out
         verify(pluggableListener).onPluggableInvalidated(eq(filter), any())
-        verify(notificationEntryManager, never()).updateNotifications(anyString())
         assertFalse(filter.shouldFilterOut(entry2HasNotRecentlyAlerted, now))
     }
 
@@ -390,7 +380,6 @@
 
     private fun verifyPipelinesInvalidated() {
         verify(pluggableListener).onPluggableInvalidated(eq(filter), any())
-        verify(notificationEntryManager).updateNotifications(anyString())
     }
 
     private fun assertExecutorIsClear() {
@@ -399,12 +388,10 @@
 
     private fun verifyPipelinesNotInvalidated() {
         verify(pluggableListener, never()).onPluggableInvalidated(eq(filter), any())
-        verify(notificationEntryManager, never()).updateNotifications(anyString())
     }
 
     private fun clearPipelineInvocations() {
         clearInvocations(pluggableListener)
-        clearInvocations(notificationEntryManager)
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/legacy/GroupEventDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/legacy/GroupEventDispatcherTest.kt
deleted file mode 100644
index c17fe6f..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/legacy/GroupEventDispatcherTest.kt
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.notification.collection.legacy
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper.RunWithLooper
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.GroupEventDispatcher
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener
-import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
-import com.android.systemui.util.mockito.mock
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@RunWithLooper
-class GroupEventDispatcherTest : SysuiTestCase() {
-    val groupMap = mutableMapOf<String, NotificationGroup>()
-    val groupTestHelper = NotificationGroupTestHelper(mContext)
-
-    private val dispatcher = GroupEventDispatcher(groupMap::get)
-    private val listener: OnGroupChangeListener = mock()
-
-    @Before
-    fun setup() {
-        dispatcher.registerGroupChangeListener(listener)
-    }
-
-    @Test
-    fun testOnGroupsChangedUnbuffered() {
-        dispatcher.notifyGroupsChanged()
-        verify(listener).onGroupsChanged()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testOnGroupsChangedBuffered() {
-        dispatcher.openBufferScope()
-        dispatcher.notifyGroupsChanged()
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verify(listener).onGroupsChanged()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testOnGroupsChangedDoubleBuffered() {
-        dispatcher.openBufferScope()
-        dispatcher.notifyGroupsChanged()
-        dispatcher.openBufferScope() // open a nested buffer scope
-        dispatcher.notifyGroupsChanged()
-        dispatcher.closeBufferScope() // should NOT flush events
-        dispatcher.notifyGroupsChanged()
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope() // this SHOULD flush events
-        verify(listener).onGroupsChanged()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testOnGroupsChangedBufferCoalesces() {
-        dispatcher.openBufferScope()
-        dispatcher.notifyGroupsChanged()
-        dispatcher.notifyGroupsChanged()
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verify(listener).onGroupsChanged()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testOnGroupCreatedIsNeverBuffered() {
-        val group = addGroup(1)
-
-        dispatcher.openBufferScope()
-        dispatcher.notifyGroupCreated(group)
-        verify(listener).onGroupCreated(group, group.groupKey)
-        verifyNoMoreInteractions(listener)
-
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testOnGroupRemovedIsNeverBuffered() {
-        val group = addGroup(1)
-
-        dispatcher.openBufferScope()
-        dispatcher.notifyGroupRemoved(group)
-        verify(listener).onGroupRemoved(group, group.groupKey)
-        verifyNoMoreInteractions(listener)
-
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideAddedUnbuffered() {
-        val group = addGroup(1)
-        val newAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = newAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, null)
-        verify(listener).onGroupAlertOverrideChanged(group, null, newAlertEntry)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideRemovedUnbuffered() {
-        val group = addGroup(1)
-        val oldAlertEntry = groupTestHelper.createChildNotification()
-        dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
-        verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, null)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideChangedUnbuffered() {
-        val group = addGroup(1)
-        val oldAlertEntry = groupTestHelper.createChildNotification()
-        val newAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = newAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
-        verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, newAlertEntry)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideChangedBuffered() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        val oldAlertEntry = groupTestHelper.createChildNotification()
-        val newAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = newAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, newAlertEntry)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideIgnoredIfRemoved() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        val oldAlertEntry = groupTestHelper.createChildNotification()
-        val newAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = newAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
-        verifyNoMoreInteractions(listener)
-        groupMap.clear()
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideMultipleChangesBuffered() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        val oldAlertEntry = groupTestHelper.createChildNotification()
-        val newAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = null
-        dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
-        group.alertOverride = newAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, null)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, newAlertEntry)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideTemporaryValueSwallowed() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        val stableAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = null
-        dispatcher.notifyAlertOverrideChanged(group, stableAlertEntry)
-        group.alertOverride = stableAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, null)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testAlertOverrideTemporaryNullSwallowed() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        val temporaryAlertEntry = groupTestHelper.createChildNotification()
-        group.alertOverride = temporaryAlertEntry
-        dispatcher.notifyAlertOverrideChanged(group, null)
-        group.alertOverride = null
-        dispatcher.notifyAlertOverrideChanged(group, temporaryAlertEntry)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testSuppressOnUnbuffered() {
-        val group = addGroup(1)
-        group.suppressed = true
-        dispatcher.notifySuppressedChanged(group)
-        verify(listener).onGroupSuppressionChanged(group, true)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testSuppressOffUnbuffered() {
-        val group = addGroup(1)
-        group.suppressed = false
-        dispatcher.notifySuppressedChanged(group)
-        verify(listener).onGroupSuppressionChanged(group, false)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testSuppressOnBuffered() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        group.suppressed = false
-        dispatcher.notifySuppressedChanged(group)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verify(listener).onGroupSuppressionChanged(group, false)
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testSuppressOnIgnoredIfRemoved() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        group.suppressed = false
-        dispatcher.notifySuppressedChanged(group)
-        verifyNoMoreInteractions(listener)
-        groupMap.clear()
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testSuppressOnOffBuffered() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        group.suppressed = true
-        dispatcher.notifySuppressedChanged(group)
-        group.suppressed = false
-        dispatcher.notifySuppressedChanged(group)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verifyNoMoreInteractions(listener)
-    }
-
-    @Test
-    fun testSuppressOnOffOnBuffered() {
-        dispatcher.openBufferScope()
-        val group = addGroup(1)
-        group.suppressed = true
-        dispatcher.notifySuppressedChanged(group)
-        group.suppressed = false
-        dispatcher.notifySuppressedChanged(group)
-        group.suppressed = true
-        dispatcher.notifySuppressedChanged(group)
-        verifyNoMoreInteractions(listener)
-        dispatcher.closeBufferScope()
-        verify(listener).onGroupSuppressionChanged(group, true)
-        verifyNoMoreInteractions(listener)
-    }
-
-    private fun addGroup(id: Int): NotificationGroup {
-        val group = NotificationGroup("group:$id")
-        groupMap[group.groupKey] = group
-        return group
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 8a7b9d3..b2dc842 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -44,8 +44,6 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifLiveData;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -85,11 +83,9 @@
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
 
     // Dependency mocks:
-    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifLiveDataStore mNotifLiveDataStore;
     @Mock private NotifLiveData<List<NotificationEntry>> mActiveNotifEntries;
     @Mock private NotificationVisibilityProvider mVisibilityProvider;
-    @Mock private NotificationEntryManager mEntryManager;
     @Mock private NotifPipeline mNotifPipeline;
     @Mock private NotificationListener mListener;
 
@@ -118,17 +114,14 @@
         mLogger = new TestableNotificationLogger(
                 mListener,
                 mUiBgExecutor,
-                mNotifPipelineFlags,
                 mNotifLiveDataStore,
                 mVisibilityProvider,
-                mEntryManager,
                 mNotifPipeline,
                 mock(StatusBarStateControllerImpl.class),
                 mBarService,
                 mExpansionStateLogger
         );
         mLogger.setUpWithContainer(mListContainer);
-        verify(mEntryManager, never()).addNotificationEntryListener(any());
         verify(mNotifPipeline).addCollectionListener(any());
     }
 
@@ -266,10 +259,8 @@
 
         TestableNotificationLogger(NotificationListener notificationListener,
                 Executor uiBgExecutor,
-                NotifPipelineFlags notifPipelineFlags,
                 NotifLiveDataStore notifLiveDataStore,
                 NotificationVisibilityProvider visibilityProvider,
-                NotificationEntryManager entryManager,
                 NotifPipeline notifPipeline,
                 StatusBarStateControllerImpl statusBarStateController,
                 IStatusBarService barService,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleFakes.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleFakes.kt
deleted file mode 100644
index 1fb4ca1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleFakes.kt
+++ /dev/null
@@ -1,31 +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.statusbar.notification.people
-
-object EmptySubscription : Subscription {
-    override fun unsubscribe() {}
-}
-
-class FakeDataSource<T>(
-    private val data: T,
-    private val subscription: Subscription = EmptySubscription
-) : DataSource<T> {
-    override fun registerListener(listener: DataListener<T>): Subscription {
-        listener.onDataChanged(data)
-        return subscription
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
deleted file mode 100644
index 5898664..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.people
-
-import android.graphics.drawable.Drawable
-import android.testing.AndroidTestingRunner
-import android.view.View
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.ActivityStarter
-import com.google.common.truth.Truth.assertThat
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
-import kotlin.reflect.KClass
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-class PeopleHubViewControllerTest : SysuiTestCase() {
-
-    @JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule()
-
-    @Mock private lateinit var mockViewBoundary: PeopleHubViewBoundary
-    @Mock private lateinit var mockActivityStarter: ActivityStarter
-
-    @Test
-    fun testBindViewModelToViewBoundary() {
-        val fakePerson1 = fakePersonViewModel("name")
-        val fakeViewModel = PeopleHubViewModel(sequenceOf(fakePerson1), true)
-
-        val mockFactory = mock(PeopleHubViewModelFactory::class.java)
-        whenever(mockFactory.createWithAssociatedClickView(any())).thenReturn(fakeViewModel)
-
-        val mockClickView = mock(View::class.java)
-        whenever(mockViewBoundary.associatedViewForClickAnimation).thenReturn(mockClickView)
-
-        val fakePersonViewAdapter1 = FakeDataListener<PersonViewModel?>()
-        val fakePersonViewAdapter2 = FakeDataListener<PersonViewModel?>()
-        whenever(mockViewBoundary.personViewAdapters)
-                .thenReturn(sequenceOf(fakePersonViewAdapter1, fakePersonViewAdapter2))
-
-        val adapter = PeopleHubViewAdapterImpl(FakeDataSource(mockFactory))
-
-        adapter.bindView(mockViewBoundary)
-
-        assertThat(fakePersonViewAdapter1.lastSeen).isEqualTo(Maybe.Just(fakePerson1))
-        assertThat(fakePersonViewAdapter2.lastSeen).isEqualTo(Maybe.Just<PersonViewModel?>(null))
-        verify(mockViewBoundary).setVisible(true)
-        verify(mockFactory).createWithAssociatedClickView(mockClickView)
-    }
-
-    @Test
-    fun testBindViewModelToViewBoundary_moreDataThanCanBeDisplayed_displaysMostRecent() {
-        val fakePerson1 = fakePersonViewModel("person1")
-        val fakePerson2 = fakePersonViewModel("person2")
-        val fakePerson3 = fakePersonViewModel("person3")
-        val fakePeople = sequenceOf(fakePerson3, fakePerson2, fakePerson1)
-        val fakeViewModel = PeopleHubViewModel(fakePeople, true)
-
-        val mockFactory = mock(PeopleHubViewModelFactory::class.java)
-        whenever(mockFactory.createWithAssociatedClickView(any())).thenReturn(fakeViewModel)
-
-        whenever(mockViewBoundary.associatedViewForClickAnimation)
-                .thenReturn(mock(View::class.java))
-
-        val fakePersonViewAdapter1 = FakeDataListener<PersonViewModel?>()
-        val fakePersonViewAdapter2 = FakeDataListener<PersonViewModel?>()
-        whenever(mockViewBoundary.personViewAdapters)
-                .thenReturn(sequenceOf(fakePersonViewAdapter1, fakePersonViewAdapter2))
-
-        val adapter = PeopleHubViewAdapterImpl(FakeDataSource(mockFactory))
-
-        adapter.bindView(mockViewBoundary)
-
-        assertThat(fakePersonViewAdapter1.lastSeen).isEqualTo(Maybe.Just(fakePerson3))
-        assertThat(fakePersonViewAdapter2.lastSeen).isEqualTo(Maybe.Just(fakePerson2))
-    }
-
-    @Test
-    fun testViewModelDataSourceTransformsModel() {
-        val fakeClickRunnable = mock(Runnable::class.java)
-        val fakePerson = fakePersonModel("id", "name", fakeClickRunnable)
-        val fakeModel = PeopleHubModel(listOf(fakePerson))
-        val fakeModelDataSource = FakeDataSource(fakeModel)
-        val factoryDataSource = PeopleHubViewModelFactoryDataSourceImpl(
-                mockActivityStarter,
-                fakeModelDataSource
-        )
-        val fakeListener = FakeDataListener<PeopleHubViewModelFactory>()
-        val mockClickView = mock(View::class.java)
-
-        factoryDataSource.registerListener(fakeListener)
-
-        val viewModel = (fakeListener.lastSeen as Maybe.Just).value
-                .createWithAssociatedClickView(mockClickView)
-        assertThat(viewModel.isVisible).isTrue()
-        val people = viewModel.people.toList()
-        assertThat(people.size).isEqualTo(1)
-        assertThat(people[0].name).isEqualTo("name")
-        assertThat(people[0].icon).isSameInstanceAs(fakePerson.avatar)
-
-        people[0].onClick()
-
-        verify(fakeClickRunnable).run()
-    }
-}
-
-/** Works around Mockito matchers returning `null` and breaking non-nullable Kotlin code. */
-private inline fun <reified T : Any> any(): T {
-    return Mockito.any() ?: createInstance(T::class)
-}
-
-/** Works around Mockito matchers returning `null` and breaking non-nullable Kotlin code. */
-private inline fun <reified T : Any> same(value: T): T {
-    return Mockito.same(value) ?: createInstance(T::class)
-}
-
-/** Creates an instance of the given class. */
-private fun <T : Any> createInstance(clazz: KClass<T>): T = castNull()
-
-/** Tricks the Kotlin compiler into assigning `null` to a non-nullable variable. */
-@Suppress("UNCHECKED_CAST")
-private fun <T> castNull(): T = null as T
-
-private fun fakePersonModel(
-    id: String,
-    name: CharSequence,
-    clickRunnable: Runnable,
-    userId: Int = 0
-): PersonModel =
-        PersonModel(id, userId, name, mock(Drawable::class.java), clickRunnable)
-
-private fun fakePersonViewModel(name: CharSequence): PersonViewModel =
-        PersonViewModel(name, mock(Drawable::class.java), mock({}.javaClass))
-
-sealed class Maybe<T> {
-    data class Just<T>(val value: T) : Maybe<T>()
-    class Nothing<T> : Maybe<T>() {
-        override fun equals(other: Any?): Boolean {
-            if (this === other) return true
-            if (javaClass != other?.javaClass) return false
-            return true
-        }
-
-        override fun hashCode(): Int {
-            return javaClass.hashCode()
-        }
-    }
-}
-
-class FakeDataListener<T> : DataListener<T> {
-
-    var lastSeen: Maybe<T> = Maybe.Nothing()
-
-    override fun onDataChanged(data: T) {
-        lastSeen = Maybe.Just(data)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
index fe2f5f0..6d687a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/FeedbackInfoTest.java
@@ -57,7 +57,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.notification.AssistantFeedbackController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 
@@ -84,8 +83,6 @@
     private StatusBarNotification mSbn;
 
     @Mock
-    private NotificationEntryManager mNotificationEntryManager;
-    @Mock
     private IStatusBarService mStatusBarService;
     @Mock
     private NotificationGutsManager mNotificationGutsManager;
@@ -94,7 +91,6 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
         mDependency.injectTestDependency(IStatusBarService.class, mStatusBarService);
         mDependency.injectTestDependency(NotificationGutsManager.class, mNotificationGutsManager);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
deleted file mode 100644
index b20f95c..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
+++ /dev/null
@@ -1,302 +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.statusbar.notification.row;
-
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
-import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
-
-import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.NotificationChannel;
-import android.content.Context;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.View;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Tests for {@link NotificationBlockingHelperManager}.
- */
-@SmallTest
-@FlakyTest
[email protected](AndroidTestingRunner.class)
[email protected]
-public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
-    private NotificationBlockingHelperManager mBlockingHelperManager;
-
-    private NotificationTestHelper mHelper;
-
-    @Mock private NotificationGutsManager mGutsManager;
-    @Mock private NotificationEntryManager mEntryManager;
-    @Mock private NotificationMenuRow mMenuRow;
-    @Mock private NotificationMenuRowPlugin.MenuItem mMenuItem;
-    @Mock private GroupMembershipManager mGroupMembershipManager;
-
-    @Before
-    public void setUp() {
-        allowTestableLooperAsMainThread();
-        MockitoAnnotations.initMocks(this);
-        when(mGutsManager.openGuts(
-                any(View.class),
-                anyInt(),
-                anyInt(),
-                any(NotificationMenuRowPlugin.MenuItem.class)))
-                .thenReturn(true);
-        when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
-
-        mHelper = new NotificationTestHelper(mContext, mDependency, TestableLooper.get(this));
-
-        mBlockingHelperManager = new NotificationBlockingHelperManager(
-                mContext, mGutsManager, mEntryManager, mock(MetricsLogger.class),
-                mGroupMembershipManager);
-        // By default, have the shade visible/expanded.
-        mBlockingHelperManager.setNotificationShadeExpanded(1f);
-    }
-
-    @Test
-    public void testDismissCurrentBlockingHelper_nullBlockingHelperRow() {
-        // By default, this shouldn't dismiss (no pointers/vars set up!)
-        assertFalse(mBlockingHelperManager.dismissCurrentBlockingHelper());
-        assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
-    }
-
-    @Test
-    public void testDismissCurrentBlockingHelper_withDetachedBlockingHelperRow() throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        row.setBlockingHelperShowing(true);
-        when(row.isAttachedToWindow()).thenReturn(false);
-        mBlockingHelperManager.setBlockingHelperRowForTest(row);
-
-        assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
-        assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
-
-        verify(mEntryManager, times(0)).updateNotifications(anyString());
-    }
-
-    @Test
-    public void testDismissCurrentBlockingHelper_withAttachedBlockingHelperRow() throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        row.setBlockingHelperShowing(true);
-        when(row.isAttachedToWindow()).thenReturn(true);
-        mBlockingHelperManager.setBlockingHelperRowForTest(row);
-
-        assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
-        assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
-
-        verify(mEntryManager).updateNotifications(anyString());
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_shown() throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-
-        assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
-
-        verify(mGutsManager).openGuts(row, 0, 0, mMenuItem);
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_notShownForMultiChannelGroup() throws Exception {
-        ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10);
-        int i = 0;
-        for (ExpandableNotificationRow childRow : groupRow.getAttachedChildren()) {
-            modifyRanking(childRow.getEntry())
-                    .setChannel(
-                            new NotificationChannel(
-                                    Integer.toString(i++), "", IMPORTANCE_DEFAULT))
-                    .build();
-        }
-
-        modifyRanking(groupRow.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-
-        assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(groupRow, mMenuRow));
-
-        verify(mGutsManager, never()).openGuts(groupRow, 0, 0, mMenuItem);
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_shownForLargeGroup() throws Exception {
-        ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10);
-        modifyRanking(groupRow.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-
-        assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(groupRow, mMenuRow));
-
-        verify(mGutsManager).openGuts(groupRow, 0, 0, mMenuItem);
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_shownForOnlyChildNotification()
-            throws Exception {
-        ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(1);
-        // Explicitly get the children container & call getViewAtPosition on it instead of the row
-        // as other factors such as view expansion may cause us to get the parent row back instead
-        // of the child row.
-        ExpandableNotificationRow childRow = groupRow.getChildrenContainer().getViewAtPosition(0);
-        modifyRanking(childRow.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        assertFalse(childRow.getIsNonblockable());
-
-        when(mGroupMembershipManager.isOnlyChildInGroup(childRow.getEntry())).thenReturn(true);
-        assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(childRow, mMenuRow));
-
-        verify(mGutsManager).openGuts(childRow, 0, 0, mMenuItem);
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_notShownDueToNeutralUserSentiment() throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEUTRAL)
-                .build();
-
-        assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_notShownDueToPositiveUserSentiment()
-            throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_POSITIVE)
-                .build();
-
-        assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_notShownDueToShadeVisibility() throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        // Hide the shade
-        mBlockingHelperManager.setNotificationShadeExpanded(0f);
-
-        assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_notShownDueToNonblockability() throws Exception {
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        when(row.getIsNonblockable()).thenReturn(true);
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-
-        assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
-    }
-
-    @Test
-    public void testPerhapsShowBlockingHelper_notShownAsNotificationIsInMultipleChildGroup()
-            throws Exception {
-        ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(2);
-        // Explicitly get the children container & call getViewAtPosition on it instead of the row
-        // as other factors such as view expansion may cause us to get the parent row back instead
-        // of the child row.
-        ExpandableNotificationRow childRow = groupRow.getChildrenContainer().getViewAtPosition(0);
-        modifyRanking(childRow.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-
-        assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(childRow, mMenuRow));
-    }
-
-    @Test
-    public void testBlockingHelperShowAndDismiss() throws Exception{
-        ExpandableNotificationRow row = createBlockableRowSpy();
-        modifyRanking(row.getEntry())
-                .setUserSentiment(USER_SENTIMENT_NEGATIVE)
-                .build();
-        when(row.isAttachedToWindow()).thenReturn(true);
-
-        // Show check
-        assertTrue(mBlockingHelperManager.perhapsShowBlockingHelper(row, mMenuRow));
-
-        verify(mGutsManager).openGuts(row, 0, 0, mMenuItem);
-
-        // Dismiss check
-        assertTrue(mBlockingHelperManager.dismissCurrentBlockingHelper());
-        assertTrue(mBlockingHelperManager.isBlockingHelperRowNull());
-
-        verify(mEntryManager).updateNotifications(anyString());
-    }
-
-    @Test
-    public void testNonBlockable_package() {
-        mBlockingHelperManager.setNonBlockablePkgs(new String[] {"banana", "strawberry:pie"});
-
-        assertFalse(mBlockingHelperManager.isNonblockable("orange", "pie"));
-
-        assertTrue(mBlockingHelperManager.isNonblockable("banana", "pie"));
-    }
-
-    @Test
-    public void testNonBlockable_channel() {
-        mBlockingHelperManager.setNonBlockablePkgs(new String[] {"banana", "strawberry:pie"});
-
-        assertFalse(mBlockingHelperManager.isNonblockable("strawberry", "shortcake"));
-
-        assertTrue(mBlockingHelperManager.isNonblockable("strawberry", "pie"));
-    }
-
-    private ExpandableNotificationRow createBlockableRowSpy() throws Exception {
-        ExpandableNotificationRow row = spy(mHelper.createRow());
-        when(row.getIsNonblockable()).thenReturn(false);
-        return row;
-    }
-
-    private ExpandableNotificationRow createBlockableGroupRowSpy(int numChildren) throws Exception {
-        ExpandableNotificationRow row = spy(mHelper.createGroup(numChildren));
-        when(row.getIsNonblockable()).thenReturn(false);
-        return row;
-    }
-}
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/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 1460e04..8be9eb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -34,7 +34,6 @@
 import android.content.res.Resources;
 import android.metrics.LogMaker;
 import android.testing.AndroidTestingRunner;
-import android.view.LayoutInflater;
 
 import androidx.test.filters.SmallTest;
 
@@ -42,11 +41,9 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.nano.MetricsProto;
-import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -61,12 +58,8 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
@@ -112,7 +105,6 @@
     @Mock private KeyguardMediaController mKeyguardMediaController;
     @Mock private SysuiStatusBarStateController mSysuiStatusBarStateController;
     @Mock private KeyguardBypassController mKeyguardBypassController;
-    @Mock private SysuiColorExtractor mColorExtractor;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
     @Mock private MetricsLogger mMetricsLogger;
     @Mock private DumpManager mDumpManager;
@@ -122,19 +114,13 @@
     @Mock private NotificationSwipeHelper mNotificationSwipeHelper;
     @Mock private CentralSurfaces mCentralSurfaces;
     @Mock private ScrimController mScrimController;
-    @Mock private NotificationGroupManagerLegacy mGroupManagerLegacy;
     @Mock private GroupExpansionManager mGroupExpansionManager;
     @Mock private SectionHeaderController mSilentHeaderController;
-    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifPipeline mNotifPipeline;
     @Mock private NotifCollection mNotifCollection;
-    @Mock private NotificationEntryManager mEntryManager;
-    @Mock private IStatusBarService mIStatusBarService;
     @Mock private UiEventLogger mUiEventLogger;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
-    @Mock private LayoutInflater mLayoutInflater;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
-    @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private ShadeController mShadeController;
     @Mock private InteractionJankMonitor mJankMonitor;
     @Mock private StackStateLogger mStackLogger;
@@ -176,12 +162,10 @@
                 mNotificationSwipeHelperBuilder,
                 mCentralSurfaces,
                 mScrimController,
-                mGroupManagerLegacy,
                 mGroupExpansionManager,
                 mSilentHeaderController,
                 mNotifPipeline,
                 mNotifCollection,
-                mEntryManager,
                 mLockscreenShadeTransitionController,
                 mShadeTransitionController,
                 mUiEventLogger,
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 8fd6842..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
@@ -3,22 +3,27 @@
 import android.annotation.DimenRes
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
+import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ShadeInterpolation.getContentAlpha
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.EmptyShadeView
+import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
-import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController
-import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertFalse
 import junit.framework.Assert.assertTrue
-import junit.framework.Assert.assertEquals
 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
@@ -26,17 +31,19 @@
 
     private val hostView = FrameLayout(context)
     private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView)
-    private val expandableViewState = ExpandableViewState()
     private val notificationRow = mock(ExpandableNotificationRow::class.java)
     private val dumpManager = mock(DumpManager::class.java)
     private val mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager::class.java)
-
+    private val notificationShelf = mock(NotificationShelf::class.java)
+    private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
+        layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
+    }
     private val ambientState = AmbientState(
-        context,
-        dumpManager,
-        SectionProvider { _, _ -> false },
-        BypassController { false },
-        mStatusBarKeyguardViewManager
+            context,
+            dumpManager,
+            /* sectionProvider */ { _, _ -> false },
+            /* bypassController */ { false },
+            mStatusBarKeyguardViewManager
     )
 
     private val testableResources = mContext.orCreateTestableResources
@@ -49,7 +56,9 @@
 
     @Before
     fun setUp() {
-        whenever(notificationRow.viewState).thenReturn(expandableViewState)
+        whenever(notificationShelf.viewState).thenReturn(ExpandableViewState())
+        whenever(notificationRow.viewState).thenReturn(ExpandableViewState())
+
         hostView.addView(notificationRow)
     }
 
@@ -60,7 +69,8 @@
 
         stackScrollAlgorithm.resetViewStates(ambientState, 0)
 
-        assertThat(expandableViewState.yTranslation).isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
+        assertThat(notificationRow.viewState.yTranslation)
+                .isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
     }
 
     @Test
@@ -75,15 +85,12 @@
         stackScrollAlgorithm.resetViewStates(ambientState, 0)
 
         // top margin presence should decrease heads up translation up to minHeadsUpTranslation
-        assertThat(expandableViewState.yTranslation).isEqualTo(minHeadsUpTranslation)
+        assertThat(notificationRow.viewState.yTranslation).isEqualTo(minHeadsUpTranslation)
     }
 
     @Test
     fun resetViewStates_emptyShadeView_isCenteredVertically() {
         stackScrollAlgorithm.initView(context)
-        val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
-            layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
-        }
         hostView.removeAllViews()
         hostView.addView(emptyShadeView)
         ambientState.layoutMaxHeight = 1280
@@ -98,6 +105,167 @@
     }
 
     @Test
+    fun resetViewStates_hunGoingToShade_viewBecomesOpaque() {
+        whenever(notificationRow.isAboveShelf).thenReturn(true)
+        ambientState.isShadeExpanded = true
+        ambientState.trackedHeadsUpRow = notificationRow
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationRow.viewState.alpha).isEqualTo(1f)
+    }
+
+    @Test
+    fun resetViewStates_expansionChanging_notificationBecomesTransparent() {
+        whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.25f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    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.6f
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        verify(notificationShelf).updateState(
+                /* algorithmState= */any(),
+                /* ambientState= */eq(ambientState)
+        )
+    }
+
+    @Test
+    fun resetViewStates_isOnKeyguard_viewBecomesTransparent() {
+        ambientState.setStatusBarState(StatusBarState.KEYGUARD)
+        ambientState.hideAmount = 0.25f
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationRow.viewState.alpha).isEqualTo(1f - ambientState.hideAmount)
+    }
+
+    @Test
+    fun resetViewStates_isOnKeyguard_emptyShadeViewBecomesTransparent() {
+        ambientState.setStatusBarState(StatusBarState.KEYGUARD)
+        ambientState.fractionToShade = 0.25f
+        stackScrollAlgorithm.initView(context)
+        hostView.removeAllViews()
+        hostView.addView(emptyShadeView)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        val expected = getContentAlpha(ambientState.fractionToShade)
+        assertThat(emptyShadeView.viewState.alpha).isEqualTo(expected)
+    }
+
+    @Test
+    fun resetViewStates_isOnKeyguard_emptyShadeViewBecomesOpaque() {
+        ambientState.setStatusBarState(StatusBarState.SHADE)
+        ambientState.fractionToShade = 0.25f
+        stackScrollAlgorithm.initView(context)
+        hostView.removeAllViews()
+        hostView.addView(emptyShadeView)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(emptyShadeView.viewState.alpha).isEqualTo(1f)
+    }
+
+    @Test
+    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
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationShelf.viewState.alpha).isEqualTo(expected)
+    }
+
+    @Test
+    fun resetViewStates_shelfTopLessThanViewTop_hidesView() {
+        notificationRow.viewState.yTranslation = 10f
+        notificationShelf.viewState.yTranslation = 0.9f
+        notificationShelf.viewState.hidden = false
+        ambientState.shelf = notificationShelf
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationRow.viewState.alpha).isEqualTo(0f)
+    }
+
+    @Test
+    fun resetViewStates_shelfTopGreaterOrEqualThanViewTop_viewAlphaDoesNotChange() {
+        val expected = notificationRow.viewState.alpha
+        notificationRow.viewState.yTranslation = 10f
+        notificationShelf.viewState.yTranslation = 10f
+        notificationShelf.viewState.hidden = false
+        ambientState.shelf = notificationShelf
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+    }
+
+    @Test
     fun getGapForLocation_onLockscreen_returnsSmallGap() {
         val gap = stackScrollAlgorithm.getGapForLocation(
                 /* fractionToShade= */ 0f, /* onKeyguard= */ true)
@@ -267,7 +435,6 @@
         assertEquals(10f, expandableViewState.yTranslation)
     }
 
-
     @Test
     fun clampHunToTop_viewYFarAboveVisibleStack_heightCollapsed() {
         val expandableViewState = ExpandableViewState()
@@ -339,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/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index 57fb976..e1f20d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -44,8 +44,8 @@
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.DisableFlagsLogger;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
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 3443ae6..14b7471 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
@@ -88,7 +88,6 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.charging.WiredChargingRippleController;
-import com.android.systemui.charging.WirelessChargingRippleController;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -128,13 +127,11 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotifPipelineFlags;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
 import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider;
@@ -210,7 +207,6 @@
     @Mock private DozeScrimController mDozeScrimController;
     @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     @Mock private BiometricUnlockController mBiometricUnlockController;
-    @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private NotificationListener mNotificationListener;
     @Mock private KeyguardViewMediator mKeyguardViewMediator;
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@@ -226,7 +222,6 @@
     @Mock private NotificationShadeWindowView mNotificationShadeWindowView;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
     @Mock private AssistManager mAssistManager;
-    @Mock private NotificationEntryManager mNotificationEntryManager;
     @Mock private NotificationGutsManager mNotificationGutsManager;
     @Mock private NotificationMediaManager mNotificationMediaManager;
     @Mock private NavigationBarController mNavigationBarController;
@@ -284,7 +279,6 @@
     @Mock private InteractionJankMonitor mJankMonitor;
     @Mock private DeviceStateManager mDeviceStateManager;
     @Mock private WiredChargingRippleController mWiredChargingRippleController;
-    @Mock private WirelessChargingRippleController mWirelessChargingRippleController;
     private ShadeController mShadeController;
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
     private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -401,7 +395,6 @@
                 new FalsingManagerFake(),
                 new FalsingCollectorFake(),
                 mBroadcastDispatcher,
-                mNotificationEntryManager,
                 mNotificationGutsManager,
                 notificationLogger,
                 mNotificationInterruptStateProvider,
@@ -467,9 +460,7 @@
                 mActivityLaunchAnimator,
                 mJankMonitor,
                 mDeviceStateManager,
-                mWiredChargingRippleController,
-                mWirelessChargingRippleController,
-                mDreamManager);
+                mWiredChargingRippleController, mDreamManager);
         when(mKeyguardViewMediator.registerCentralSurfaces(
                 any(CentralSurfacesImpl.class),
                 any(NotificationPanelViewController.class),
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)
[email protected](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/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 6cf1a12..ba5f503 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -17,6 +17,9 @@
 package com.android.systemui.statusbar.phone;
 
 
+import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
+import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
+
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 
@@ -49,6 +52,7 @@
 import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.NotificationPanelViewController;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserInfoTracker;
@@ -118,6 +122,7 @@
     @Mock
     private StatusBarUserInfoTracker mStatusBarUserInfoTracker;
     @Mock private SecureSettings mSecureSettings;
+    @Mock private CommandQueue mCommandQueue;
 
     private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
     private KeyguardStatusBarView mKeyguardStatusBarView;
@@ -137,6 +142,7 @@
             mKeyguardStatusBarView =
                     spy((KeyguardStatusBarView) LayoutInflater.from(mContext)
                             .inflate(R.layout.keyguard_status_bar, null));
+            when(mKeyguardStatusBarView.getDisplay()).thenReturn(mContext.getDisplay());
         });
 
         mController = createController();
@@ -165,6 +171,7 @@
                 mStatusBarUserSwitcherController,
                 mStatusBarUserInfoTracker,
                 mSecureSettings,
+                mCommandQueue,
                 mFakeExecutor
         );
     }
@@ -176,6 +183,7 @@
         verify(mConfigurationController).addCallback(any());
         verify(mAnimationScheduler).addCallback(any());
         verify(mUserInfoController).addCallback(any());
+        verify(mCommandQueue).addCallback(any());
         verify(mStatusBarIconController).addIconGroup(any());
         verify(mUserManager).isUserSwitcherEnabled(anyBoolean());
     }
@@ -214,6 +222,7 @@
         verify(mConfigurationController).removeCallback(any());
         verify(mAnimationScheduler).removeCallback(any());
         verify(mUserInfoController).removeCallback(any());
+        verify(mCommandQueue).removeCallback(any());
         verify(mStatusBarIconController).removeIconGroup(any());
     }
 
@@ -280,6 +289,17 @@
     }
 
     @Test
+    public void updateViewState_paramVisibleButIsDisabled_viewIsInvisible() {
+        mController.onViewAttached();
+        setDisableSystemIcons(true);
+
+        mController.updateViewState(1f, View.VISIBLE);
+
+        // Since we're disabled, we stay invisible
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    @Test
     public void updateViewState_notKeyguardState_nothingUpdated() {
         mController.onViewAttached();
         updateStateToNotKeyguard();
@@ -359,6 +379,50 @@
     }
 
     @Test
+    public void updateViewState_disableSystemInfoFalse_viewShown() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        setDisableSystemInfo(false);
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateViewState_disableSystemInfoTrue_viewHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        setDisableSystemInfo(true);
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    @Test
+    public void updateViewState_disableSystemIconsFalse_viewShown() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        setDisableSystemIcons(false);
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void updateViewState_disableSystemIconsTrue_viewHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        setDisableSystemIcons(true);
+
+        mController.updateViewState();
+
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
+    @Test
     public void setAlpha_explicitAlpha_setsExplicitAlpha() {
         mController.onViewAttached();
         updateStateToKeyguard();
@@ -485,6 +549,19 @@
         callback.onStateChanged(state);
     }
 
+    @Test
+    public void animateKeyguardStatusBarIn_isDisabled_viewStillHidden() {
+        mController.onViewAttached();
+        updateStateToKeyguard();
+        setDisableSystemInfo(true);
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+
+        mController.animateKeyguardStatusBarIn();
+
+        // Since we're disabled, we don't actually animate in and stay invisible
+        assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+    }
+
     /**
      * Calls {@link com.android.keyguard.KeyguardUpdateMonitorCallback#onFinishedGoingToSleep(int)}
      * to ensure values are updated properly.
@@ -498,6 +575,25 @@
         callback.onFinishedGoingToSleep(0);
     }
 
+    private void setDisableSystemInfo(boolean disabled) {
+        CommandQueue.Callbacks callback = getCommandQueueCallback();
+        int disabled1 = disabled ? DISABLE_SYSTEM_INFO : 0;
+        callback.disable(mContext.getDisplayId(), disabled1, 0, false);
+    }
+
+    private void setDisableSystemIcons(boolean disabled) {
+        CommandQueue.Callbacks callback = getCommandQueueCallback();
+        int disabled2 = disabled ? DISABLE2_SYSTEM_ICONS : 0;
+        callback.disable(mContext.getDisplayId(), 0, disabled2, false);
+    }
+
+    private CommandQueue.Callbacks getCommandQueueCallback() {
+        ArgumentCaptor<CommandQueue.Callbacks> captor =
+                ArgumentCaptor.forClass(CommandQueue.Callbacks.class);
+        verify(mCommandQueue).addCallback(captor.capture());
+        return captor.getValue();
+    }
+
     private static class TestNotificationPanelViewStateProvider
             implements NotificationPanelViewController.NotificationPanelViewStateProvider {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
new file mode 100644
index 0000000..64dee95
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone
+
+import android.app.AlarmManager
+import android.app.IActivityManager
+import android.app.admin.DevicePolicyManager
+import android.content.SharedPreferences
+import android.os.UserManager
+import android.telecom.TelecomManager
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.privacy.PrivacyItemController
+import com.android.systemui.privacy.logging.PrivacyLogger
+import com.android.systemui.screenrecord.RecordingController
+import com.android.systemui.statusbar.CommandQueue
+import com.android.systemui.statusbar.policy.BluetoothController
+import com.android.systemui.statusbar.policy.CastController
+import com.android.systemui.statusbar.policy.DataSaverController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HotspotController
+import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.statusbar.policy.LocationController
+import com.android.systemui.statusbar.policy.NextAlarmController
+import com.android.systemui.statusbar.policy.RotationLockController
+import com.android.systemui.statusbar.policy.SensorPrivacyController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.statusbar.policy.ZenModeController
+import com.android.systemui.util.RingerModeTracker
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.time.DateFormatUtil
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Answers
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+@SmallTest
+class PhoneStatusBarPolicyTest : SysuiTestCase() {
+
+    companion object {
+        private const val ALARM_SLOT = "alarm"
+    }
+
+    @Mock
+    private lateinit var iconController: StatusBarIconController
+    @Mock
+    private lateinit var commandQueue: CommandQueue
+    @Mock
+    private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock
+    private lateinit var castController: CastController
+    @Mock
+    private lateinit var hotspotController: HotspotController
+    @Mock
+    private lateinit var bluetoothController: BluetoothController
+    @Mock
+    private lateinit var nextAlarmController: NextAlarmController
+    @Mock
+    private lateinit var userInfoController: UserInfoController
+    @Mock
+    private lateinit var rotationLockController: RotationLockController
+    @Mock
+    private lateinit var dataSaverController: DataSaverController
+    @Mock
+    private lateinit var zenModeController: ZenModeController
+    @Mock
+    private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock
+    private lateinit var keyguardStateController: KeyguardStateController
+    @Mock
+    private lateinit var locationController: LocationController
+    @Mock
+    private lateinit var sensorPrivacyController: SensorPrivacyController
+    @Mock
+    private lateinit var iActivityManager: IActivityManager
+    @Mock
+    private lateinit var alarmManager: AlarmManager
+    @Mock
+    private lateinit var userManager: UserManager
+    @Mock
+    private lateinit var devicePolicyManager: DevicePolicyManager
+    @Mock
+    private lateinit var recordingController: RecordingController
+    @Mock
+    private lateinit var telecomManager: TelecomManager
+    @Mock
+    private lateinit var sharedPreferences: SharedPreferences
+    @Mock
+    private lateinit var dateFormatUtil: DateFormatUtil
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private lateinit var ringerModeTracker: RingerModeTracker
+    @Mock
+    private lateinit var privacyItemController: PrivacyItemController
+    @Mock
+    private lateinit var privacyLogger: PrivacyLogger
+    @Captor
+    private lateinit var alarmCallbackCaptor:
+            ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
+
+    private lateinit var executor: FakeExecutor
+    private lateinit var statusBarPolicy: PhoneStatusBarPolicy
+    private lateinit var testableLooper: TestableLooper
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        executor = FakeExecutor(FakeSystemClock())
+        testableLooper = TestableLooper.get(this)
+        context.orCreateTestableResources.addOverride(
+                com.android.internal.R.string.status_bar_alarm_clock,
+                ALARM_SLOT
+        )
+        statusBarPolicy = createStatusBarPolicy()
+    }
+
+    @Test
+    fun testDeviceNotProvisioned_alarmIconNotShown() {
+        val alarmInfo = createAlarmInfo()
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+        statusBarPolicy.init()
+        verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+
+        whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+        alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+        verify(iconController, never()).setIconVisibility(ALARM_SLOT, true)
+    }
+
+    @Test
+    fun testDeviceProvisioned_alarmIconShown() {
+        val alarmInfo = createAlarmInfo()
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+        statusBarPolicy.init()
+
+        verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+        whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+        alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+        verify(iconController).setIconVisibility(ALARM_SLOT, true)
+    }
+
+    @Test
+    fun testDeviceProvisionedChanged_alarmIconShownAfterCurrentUserSetup() {
+        val alarmInfo = createAlarmInfo()
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(false)
+        statusBarPolicy.init()
+
+        verify(nextAlarmController).addCallback(capture(alarmCallbackCaptor))
+        whenever(alarmManager.getNextAlarmClock(anyInt())).thenReturn(alarmInfo)
+
+        alarmCallbackCaptor.value.onNextAlarmChanged(alarmInfo)
+        verify(iconController, never()).setIconVisibility(ALARM_SLOT, true)
+
+        whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+        statusBarPolicy.onUserSetupChanged()
+        verify(iconController).setIconVisibility(ALARM_SLOT, true)
+    }
+
+    private fun createAlarmInfo(): AlarmManager.AlarmClockInfo {
+        return AlarmManager.AlarmClockInfo(10L, null)
+    }
+
+    private fun createStatusBarPolicy(): PhoneStatusBarPolicy {
+        return PhoneStatusBarPolicy(
+                iconController,
+                commandQueue,
+                broadcastDispatcher,
+                executor,
+                testableLooper.looper,
+                context.resources,
+                castController,
+                hotspotController,
+                bluetoothController,
+                nextAlarmController,
+                userInfoController,
+                rotationLockController,
+                dataSaverController,
+                zenModeController,
+                deviceProvisionedController,
+                keyguardStateController,
+                locationController,
+                sensorPrivacyController,
+                iActivityManager,
+                alarmManager,
+                userManager,
+                devicePolicyManager,
+                recordingController,
+                telecomManager,
+                /* displayId = */ 0,
+                sharedPreferences,
+                dateFormatUtil,
+                ringerModeTracker,
+                privacyItemController,
+                privacyLogger
+        )
+    }
+}
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/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index a6b7e51..de7db74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -20,7 +20,10 @@
 
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
@@ -30,12 +33,12 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.statusbar.StatusBarIcon;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
 import com.android.systemui.statusbar.StatusIconDisplayable;
+import com.android.systemui.statusbar.connectivity.ui.MobileContextProvider;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
@@ -55,16 +58,19 @@
 @SmallTest
 public class StatusBarIconControllerTest extends LeakCheckedTest {
 
+    private MobileContextProvider mMobileContextProvider = mock(MobileContextProvider.class);
+
     @Before
     public void setup() {
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
-        mDependency.injectMockDependency(DarkIconDispatcher.class);
+        // For testing, ignore context overrides
+        when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
     }
 
     @Test
     public void testSetCalledOnAdd_IconManager() {
         LinearLayout layout = new LinearLayout(mContext);
-        TestIconManager manager = new TestIconManager(layout);
+        TestIconManager manager = new TestIconManager(layout, mMobileContextProvider);
         testCallOnAdd_forManager(manager);
     }
 
@@ -73,9 +79,10 @@
         LinearLayout layout = new LinearLayout(mContext);
         TestDarkIconManager manager = new TestDarkIconManager(
                 layout,
-                mock(FeatureFlags.class),
                 mock(StatusBarPipelineFlags.class),
-                () -> mock(WifiViewModel.class));
+                () -> mock(WifiViewModel.class),
+                mMobileContextProvider,
+                mock(DarkIconDispatcher.class));
         testCallOnAdd_forManager(manager);
     }
 
@@ -114,10 +121,15 @@
 
         TestDarkIconManager(
                 LinearLayout group,
-                FeatureFlags featureFlags,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider) {
-            super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
+                Provider<WifiViewModel> wifiViewModelProvider,
+                MobileContextProvider contextProvider,
+                DarkIconDispatcher darkIconDispatcher) {
+            super(group,
+                    statusBarPipelineFlags,
+                    wifiViewModelProvider,
+                    contextProvider,
+                    darkIconDispatcher);
         }
 
         @Override
@@ -151,11 +163,11 @@
     }
 
     private static class TestIconManager extends IconManager implements TestableIconManager {
-        TestIconManager(ViewGroup group) {
+        TestIconManager(ViewGroup group, MobileContextProvider contextProvider) {
             super(group,
-                    mock(FeatureFlags.class),
                     mock(StatusBarPipelineFlags.class),
-                    () -> mock(WifiViewModel.class));
+                    () -> mock(WifiViewModel.class),
+                    contextProvider);
         }
 
         @Override
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/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 2b80508..c409857 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -66,7 +66,6 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -102,8 +101,6 @@
     @Mock
     private AssistManager mAssistManager;
     @Mock
-    private NotificationEntryManager mEntryManager;
-    @Mock
     private ActivityStarter mActivityStarter;
     @Mock
     private NotificationClickNotifier mClickNotifier;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 1ec4de9..c3a7e65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -37,7 +37,6 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -55,7 +54,6 @@
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 public class StatusBarRemoteInputCallbackTest extends SysuiTestCase {
-    @Mock private NotificationEntryManager mEntryManager;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private com.android.systemui.shade.ShadeController mShadeController;
     @Mock private NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@@ -71,7 +69,6 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         mDependency.injectTestDependency(DeviceProvisionedController.class,
                 mDeviceProvisionedController);
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
index 1ee8875..65e2964 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentLoggerTest.kt
@@ -21,12 +21,12 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.log.LogcatEchoTracker
-import com.android.systemui.statusbar.DisableFlagsLogger
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger
 import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.mockito.Mockito.mock
 import java.io.PrintWriter
 import java.io.StringWriter
+import org.junit.Test
+import org.mockito.Mockito.mock
 
 @SmallTest
 class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index ceaceb4..faadd24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -55,8 +55,8 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.DisableFlagsLogger;
 import com.android.systemui.statusbar.OperatorNameViewController;
+import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
 import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
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/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
index 9829271..d070ba0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
@@ -473,6 +473,40 @@
         job.cancel()
     }
 
+    /** Regression test for b/244173280. */
+    @Test
+    fun wifiNetwork_multipleSubscribers_newSubscribersGetCurrentValue() = runBlocking(IMMEDIATE) {
+        var latest1: WifiNetworkModel? = null
+        val job1 = underTest
+            .wifiNetwork
+            .onEach { latest1 = it }
+            .launchIn(this)
+
+        getNetworkCallback()
+            .onCapabilitiesChanged(NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO))
+
+        assertThat(latest1 is WifiNetworkModel.Active).isTrue()
+        val latest1Active = latest1 as WifiNetworkModel.Active
+        assertThat(latest1Active.networkId).isEqualTo(NETWORK_ID)
+        assertThat(latest1Active.ssid).isEqualTo(SSID)
+
+        // WHEN we add a second subscriber after having already emitted a value
+        var latest2: WifiNetworkModel? = null
+        val job2 = underTest
+            .wifiNetwork
+            .onEach { latest2 = it }
+            .launchIn(this)
+
+        // THEN the second subscribe receives the already-emitted value
+        assertThat(latest2 is WifiNetworkModel.Active).isTrue()
+        val latest2Active = latest2 as WifiNetworkModel.Active
+        assertThat(latest2Active.networkId).isEqualTo(NETWORK_ID)
+        assertThat(latest2Active.ssid).isEqualTo(SSID)
+
+        job1.cancel()
+        job2.cancel()
+    }
+
     @Test
     fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
         underTest = WifiRepositoryImpl(
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 0dd6cbb7..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
@@ -28,6 +28,7 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.qs.tiles.UserDetailItemView
+import com.android.systemui.user.data.source.UserRecord
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertTrue
@@ -38,8 +39,8 @@
 import org.mockito.ArgumentMatchers.anyBoolean
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 
 @RunWith(AndroidTestingRunner::class)
@@ -56,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
@@ -186,13 +185,14 @@
     }
 
     private fun createUserRecord(isCurrentUser: Boolean, isGuestUser: Boolean) =
-            UserSwitcherController.UserRecord(
-                    userInfo,
-                    picture,
-                    isGuestUser,
-                    isCurrentUser,
-                    false /* isAddUser */,
-                    false /* isRestricted */,
-                    true /* isSwitchToEnabled */,
-                    false /* isAddSupervisedUser */)
+        UserRecord(
+            UserInfo(0 /* id */, "name", 0 /* flags */),
+            picture,
+            isGuestUser,
+            isCurrentUser,
+            false /* isAddUser */,
+            false /* isRestricted */,
+            true /* isSwitchToEnabled */,
+            false /* isAddSupervisedUser */
+        )
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
index 359a780..8dcd4bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/UserSwitcherControllerTest.kt
@@ -56,6 +56,7 @@
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shade.NotificationShadeWindowView
 import com.android.systemui.telephony.TelephonyListenerManager
+import com.android.systemui.user.data.source.UserRecord
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
@@ -235,15 +236,16 @@
 
     @Test
     fun testSwitchUser_parentDialogDismissed() {
-        val otherUserRecord = UserSwitcherController.UserRecord(
-                secondaryUser,
-                picture,
-                false /* guest */,
-                false /* current */,
-                false /* isAddUser */,
-                false /* isRestricted */,
-                true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+        val otherUserRecord = UserRecord(
+            secondaryUser,
+            picture,
+            false /* guest */,
+            false /* current */,
+            false /* isAddUser */,
+            false /* isRestricted */,
+            true /* isSwitchToEnabled */,
+            false /* isAddSupervisedUser */
+        )
         `when`(userTracker.userId).thenReturn(ownerId)
         `when`(userTracker.userInfo).thenReturn(ownerInfo)
 
@@ -255,7 +257,8 @@
 
     @Test
     fun testAddGuest_okButtonPressed() {
-        val emptyGuestUserRecord = UserSwitcherController.UserRecord(
+        val emptyGuestUserRecord =
+            UserRecord(
                 null,
                 null,
                 true /* guest */,
@@ -263,7 +266,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(ownerId)
         `when`(userTracker.userInfo).thenReturn(ownerInfo)
 
@@ -282,7 +286,8 @@
 
     @Test
     fun testAddGuest_parentDialogDismissed() {
-        val emptyGuestUserRecord = UserSwitcherController.UserRecord(
+        val emptyGuestUserRecord =
+            UserRecord(
                 null,
                 null,
                 true /* guest */,
@@ -290,7 +295,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(ownerId)
         `when`(userTracker.userInfo).thenReturn(ownerInfo)
 
@@ -305,7 +311,8 @@
 
     @Test
     fun testRemoveGuest_removeButtonPressed_isLogged() {
-        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+        val currentGuestUserRecord =
+            UserRecord(
                 guestInfo,
                 picture,
                 true /* guest */,
@@ -313,7 +320,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(guestInfo.id)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
@@ -331,7 +339,8 @@
 
     @Test
     fun testRemoveGuest_removeButtonPressed_dialogDismissed() {
-        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+        val currentGuestUserRecord =
+            UserRecord(
                 guestInfo,
                 picture,
                 true /* guest */,
@@ -339,7 +348,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(guestInfo.id)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
@@ -353,7 +363,8 @@
 
     @Test
     fun testRemoveGuest_dialogShowerUsed() {
-        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+        val currentGuestUserRecord =
+            UserRecord(
                 guestInfo,
                 picture,
                 true /* guest */,
@@ -361,7 +372,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(guestInfo.id)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
@@ -376,7 +388,8 @@
 
     @Test
     fun testRemoveGuest_cancelButtonPressed_isNotLogged() {
-        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+        val currentGuestUserRecord =
+            UserRecord(
                 guestInfo,
                 picture,
                 true /* guest */,
@@ -384,7 +397,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(guestId)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
@@ -398,7 +412,8 @@
 
     @Test
     fun testWipeGuest_startOverButtonPressed_isLogged() {
-        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+        val currentGuestUserRecord =
+            UserRecord(
                 guestInfo,
                 picture,
                 true /* guest */,
@@ -406,7 +421,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(guestId)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
@@ -433,7 +449,8 @@
 
     @Test
     fun testWipeGuest_continueButtonPressed_isLogged() {
-        val currentGuestUserRecord = UserSwitcherController.UserRecord(
+        val currentGuestUserRecord =
+            UserRecord(
                 guestInfo,
                 picture,
                 true /* guest */,
@@ -441,7 +458,8 @@
                 false /* isAddUser */,
                 false /* isRestricted */,
                 true /* isSwitchToEnabled */,
-                false /* isAddSupervisedUser */)
+                false /* isAddSupervisedUser */
+            )
         `when`(userTracker.userId).thenReturn(guestId)
         `when`(userTracker.userInfo).thenReturn(guestInfo)
 
@@ -470,11 +488,13 @@
     @Test
     fun test_getCurrentUserName_shouldReturnNameOfTheCurrentUser() {
         fun addUser(id: Int, name: String, isCurrent: Boolean) {
-            userSwitcherController.users.add(UserSwitcherController.UserRecord(
+            userSwitcherController.users.add(
+                UserRecord(
                     UserInfo(id, name, 0),
                     null, false, isCurrent, false,
                     false, false, false
-            ))
+                )
+            )
         }
         val bgUserName = "background_user"
         val fgUserName = "foreground_user"
@@ -593,7 +613,7 @@
     @Test
     fun onUserItemClicked_guest_runsOnBgThread() {
         val dialogShower = mock(UserSwitchDialogController.DialogShower::class.java)
-        val guestUserRecord = UserSwitcherController.UserRecord(
+        val guestUserRecord = UserRecord(
             null,
             picture,
             true /* guest */,
@@ -601,7 +621,8 @@
             false /* isAddUser */,
             false /* isRestricted */,
             true /* isSwitchToEnabled */,
-            false /* isAddSupervisedUser */)
+            false /* isAddSupervisedUser */
+        )
 
         userSwitcherController.onUserListItemClicked(guestUserRecord, dialogShower)
         assertTrue(bgExecutor.numPending() > 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
similarity index 61%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index f133068..e616c26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
 
 import android.content.Context
 import android.content.pm.ApplicationInfo
@@ -30,6 +30,7 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -38,7 +39,6 @@
 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
@@ -52,8 +52,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-class MediaTttChipControllerCommonTest : SysuiTestCase() {
-    private lateinit var controllerCommon: TestControllerCommon
+class TemporaryViewDisplayControllerTest : SysuiTestCase() {
+    private lateinit var underTest: TestController
 
     private lateinit var fakeClock: FakeSystemClock
     private lateinit var fakeExecutor: FakeExecutor
@@ -72,8 +72,6 @@
     @Mock
     private lateinit var windowManager: WindowManager
     @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
     private lateinit var powerManager: PowerManager
 
     @Before
@@ -97,11 +95,10 @@
         fakeClock = FakeSystemClock()
         fakeExecutor = FakeExecutor(fakeClock)
 
-        controllerCommon = TestControllerCommon(
+        underTest = TestController(
                 context,
                 logger,
                 windowManager,
-                viewUtil,
                 fakeExecutor,
                 accessibilityManager,
                 configurationController,
@@ -110,43 +107,43 @@
     }
 
     @Test
-    fun displayChip_chipAdded() {
-        controllerCommon.displayChip(getState())
+    fun displayView_viewAdded() {
+        underTest.displayView(getState())
 
         verify(windowManager).addView(any(), any())
     }
 
     @Test
-    fun displayChip_screenOff_screenWakes() {
+    fun displayView_screenOff_screenWakes() {
         whenever(powerManager.isScreenOn).thenReturn(false)
 
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
         verify(powerManager).wakeUp(any(), any(), any())
     }
 
     @Test
-    fun displayChip_screenAlreadyOn_screenNotWoken() {
+    fun displayView_screenAlreadyOn_screenNotWoken() {
         whenever(powerManager.isScreenOn).thenReturn(true)
 
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
         verify(powerManager, never()).wakeUp(any(), any(), any())
     }
 
     @Test
-    fun displayChip_twice_chipNotAddedTwice() {
-        controllerCommon.displayChip(getState())
+    fun displayView_twice_viewNotAddedTwice() {
+        underTest.displayView(getState())
         reset(windowManager)
 
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
         verify(windowManager, never()).addView(any(), any())
     }
 
     @Test
-    fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
+    fun displayView_viewDoesNotDisappearsBeforeTimeout() {
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
         reset(windowManager)
 
         fakeClock.advanceTime(TIMEOUT_MS - 1)
@@ -155,9 +152,9 @@
     }
 
     @Test
-    fun displayChip_chipDisappearsAfterTimeout() {
+    fun displayView_viewDisappearsAfterTimeout() {
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
         reset(windowManager)
 
         fakeClock.advanceTime(TIMEOUT_MS + 1)
@@ -166,176 +163,176 @@
     }
 
     @Test
-    fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
-        // First, display the chip
+    fun displayView_calledAgainBeforeTimeout_timeoutReset() {
+        // First, display the view
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
 
-        // After some time, re-display the chip
+        // After some time, re-display the view
         val waitTime = 1000L
         fakeClock.advanceTime(waitTime)
-        controllerCommon.displayChip(getState())
+        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 chip
+        // Verify we didn't hide the view
         verify(windowManager, never()).removeView(any())
     }
 
     @Test
-    fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
-        // First, display the chip
+    fun displayView_calledAgainBeforeTimeout_eventuallyTimesOut() {
+        // First, display the view
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
 
-        // After some time, re-display the chip
+        // After some time, re-display the view
         fakeClock.advanceTime(1000L)
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
-        // Ensure we still hide the chip eventually
+        // Ensure we still hide the view 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"))
+    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(controllerCommon.mostRecentChipInfo?.name).isEqualTo("Second name")
+        assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
     }
 
     @Test
-    fun removeChip_chipRemovedAndRemovalLogged() {
-        // First, add the chip
-        controllerCommon.displayChip(getState())
+    fun removeView_viewRemovedAndRemovalLogged() {
+        // First, add the view
+        underTest.displayView(getState())
 
         // Then, remove it
         val reason = "test reason"
-        controllerCommon.removeChip(reason)
+        underTest.removeView(reason)
 
         verify(windowManager).removeView(any())
         verify(logger).logChipRemoval(reason)
     }
 
     @Test
-    fun removeChip_noAdd_viewNotRemoved() {
-        controllerCommon.removeChip("reason")
+    fun removeView_noAdd_viewNotRemoved() {
+        underTest.removeView("reason")
 
         verify(windowManager, never()).removeView(any())
     }
 
     @Test
     fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+        underTest.setIcon(view, appPackageName = null, appIconDrawableOverride = null)
 
-        assertThat(chipView.getAppIconView().drawable).isNotNull()
+        assertThat(view.getAppIconView().drawable).isNotNull()
     }
 
     @Test
     fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(
-            chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+        underTest.setIcon(
+            view, appPackageName = "fakePackageName", appIconDrawableOverride = null
         )
 
-        assertThat(chipView.getAppIconView().drawable).isNotNull()
+        assertThat(view.getAppIconView().drawable).isNotNull()
     }
 
     @Test
     fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
+        underTest.setIcon(view, PACKAGE_NAME, appIconDrawableOverride = null, null)
 
-        assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
+        assertThat(view.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
     }
 
     @Test
     fun setIcon_hasAppIconDrawable_iconIsDrawable() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
         val drawable = context.getDrawable(R.drawable.ic_alarm)!!
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null)
+        underTest.setIcon(view, PACKAGE_NAME, drawable, null)
 
-        assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+        assertThat(view.getAppIconView().drawable).isEqualTo(drawable)
     }
 
     @Test
     fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+        underTest.setIcon(view, appPackageName = null, appNameOverride = null)
 
-        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+        assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
     }
 
     @Test
     fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(
-            chipView, appPackageName = "fakePackageName", appNameOverride = null
+        underTest.setIcon(
+            view, appPackageName = "fakePackageName", appNameOverride = null
         )
 
-        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+        assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
     }
 
     @Test
     fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null)
+        underTest.setIcon(view, PACKAGE_NAME, null, appNameOverride = null)
 
-        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+        assertThat(view.getAppIconView().contentDescription).isEqualTo(APP_NAME)
     }
 
     @Test
     fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
         val appName = "Override App Name"
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName)
+        underTest.setIcon(view, PACKAGE_NAME, null, appName)
 
-        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
+        assertThat(view.getAppIconView().contentDescription).isEqualTo(appName)
     }
 
     @Test
     fun setIcon_iconSizeMatchesGetIconSize() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, PACKAGE_NAME)
-        chipView.measure(
+        underTest.setIcon(view, PACKAGE_NAME)
+        view.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)
+        assertThat(view.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+        assertThat(view.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
     }
 
-    private fun getState(name: String = "name") = ChipInfo(name)
+    private fun getState(name: String = "name") = ViewInfo(name)
 
-    private fun getChipView(): ViewGroup {
+    private fun getView(): ViewGroup {
         val viewCaptor = ArgumentCaptor.forClass(View::class.java)
         verify(windowManager).addView(viewCaptor.capture(), any())
         return viewCaptor.value as ViewGroup
@@ -349,37 +346,35 @@
         return callbackCaptor.value
     }
 
-    inner class TestControllerCommon(
+    inner class TestController(
         context: Context,
         logger: MediaTttLogger,
         windowManager: WindowManager,
-        viewUtil: ViewUtil,
         @Main mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
-    ) : MediaTttChipControllerCommon<ChipInfo>(
+    ) : TemporaryViewDisplayController<ViewInfo>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
         powerManager,
         R.layout.media_ttt_chip,
     ) {
-        var mostRecentChipInfo: ChipInfo? = null
+        var mostRecentViewInfo: ViewInfo? = null
 
         override val windowLayoutParams = commonWindowLayoutParams
-        override fun updateChipView(newChipInfo: ChipInfo, currentChipView: ViewGroup) {
-            super.updateChipView(newChipInfo, currentChipView)
-            mostRecentChipInfo = newChipInfo
+        override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) {
+            super.updateView(newInfo, currentView)
+            mostRecentViewInfo = newInfo
         }
         override fun getIconSize(isAppIcon: Boolean): Int = ICON_SIZE
     }
 
-    inner class ChipInfo(val name: String) : ChipInfoCommon {
+    inner class ViewInfo(val name: String) : TemporaryViewInfo {
         override fun getTimeoutMs() = 1L
     }
 }
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..439beaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/UserSwitcherActivityTest.kt
@@ -24,9 +24,11 @@
 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.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -54,6 +56,10 @@
     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>
 
     @Before
     fun setUp() {
@@ -61,11 +67,12 @@
         activity = UserSwitcherActivity(
             userSwitcherController,
             broadcastDispatcher,
-            layoutInflater,
             falsingCollector,
             falsingManager,
             userManager,
-            userTracker
+            userTracker,
+            flags,
+            viewModelFactoryLazy,
         )
     }
 
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
new file mode 100644
index 0000000..7df7077
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -0,0 +1,190 @@
+/*
+ * 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.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
+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
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class PairwiseFlowTest : SysuiTestCase() {
+    @Test
+    fun simple() = runBlocking {
+        assertThatFlow((1..3).asFlow().pairwise())
+            .emitsExactly(
+                WithPrev(1, 2),
+                WithPrev(2, 3),
+            )
+    }
+
+    @Test
+    fun notEnough() = runBlocking {
+        assertThatFlow(flowOf(1).pairwise()).emitsNothing()
+    }
+
+    @Test
+    fun withInit() = runBlocking {
+        assertThatFlow(flowOf(2).pairwise(initialValue = 1))
+            .emitsExactly(WithPrev(1, 2))
+    }
+
+    @Test
+    fun notEnoughWithInit() = runBlocking {
+        assertThatFlow(emptyFlow<Int>().pairwise(initialValue = 1)).emitsNothing()
+    }
+
+    @Test
+    fun withStateFlow() = runBlocking(Dispatchers.Main.immediate) {
+        val state = MutableStateFlow(1)
+        val stop = MutableSharedFlow<Unit>()
+
+        val stoppable = merge(state, stop)
+            .takeWhile { it is Int }
+            .filterIsInstance<Int>()
+
+        val job1 = launch {
+            assertThatFlow(stoppable.pairwise()).emitsExactly(WithPrev(1, 2))
+        }
+        state.value = 2
+        val job2 = launch { assertThatFlow(stoppable.pairwise()).emitsNothing() }
+
+        stop.emit(Unit)
+
+        assertThatJob(job1).isCompleted()
+        assertThatJob(job2).isCompleted()
+    }
+}
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SetChangesFlowTest : SysuiTestCase() {
+    @Test
+    fun simple() = runBlocking {
+        assertThatFlow(
+            flowOf(setOf(1, 2, 3), setOf(2, 3, 4)).setChanges()
+        ).emitsExactly(
+            SetChanges(
+                added = setOf(1, 2, 3),
+                removed = emptySet(),
+            ),
+            SetChanges(
+                added = setOf(4),
+                removed = setOf(1),
+            ),
+        )
+    }
+
+    @Test
+    fun onlyOneEmission() = runBlocking {
+        assertThatFlow(flowOf(setOf(1)).setChanges())
+            .emitsExactly(
+                SetChanges(
+                    added = setOf(1),
+                    removed = emptySet(),
+                )
+            )
+    }
+
+    @Test
+    fun fromEmptySet() = runBlocking {
+        assertThatFlow(flowOf(emptySet(), setOf(1, 2)).setChanges())
+            .emitsExactly(
+                SetChanges(
+                    removed = emptySet(),
+                    added = setOf(1, 2),
+                )
+            )
+    }
+
+    @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 {
+    suspend fun emitsExactly(vararg emissions: T) =
+        assertThat(flow.toList()).containsExactly(*emissions).inOrder()
+    suspend fun emitsNothing() =
+        assertThat(flow.toList()).isEmpty()
+}
+
+private fun assertThatJob(job: Job) = object {
+    fun isCompleted() = assertThat(job.isCompleted).isTrue()
+}
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/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index 312db2d..2e74bf5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -85,6 +85,8 @@
     @Mock
     MediaOutputDialogFactory mMediaOutputDialogFactory;
     @Mock
+    VolumePanelFactory mVolumePanelFactory;
+    @Mock
     ActivityStarter mActivityStarter;
     @Mock
     InteractionJankMonitor mInteractionJankMonitor;
@@ -102,6 +104,7 @@
                 mDeviceProvisionedController,
                 mConfigurationController,
                 mMediaOutputDialogFactory,
+                mVolumePanelFactory,
                 mActivityStarter,
                 mInteractionJankMonitor);
         mDialog.init(0, null);
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/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 5d63632..09da52e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -99,7 +99,6 @@
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -162,8 +161,6 @@
     @Mock
     private CommonNotifCollection mCommonNotifCollection;
     @Mock
-    private NotificationGroupManagerLegacy mNotificationGroupManager;
-    @Mock
     private BubblesManager.NotifCallback mNotifCallback;
     @Mock
     private WindowManager mWindowManager;
@@ -389,7 +386,6 @@
                 interruptionStateProvider,
                 mZenModeController,
                 mLockscreenUserManager,
-                mNotificationGroupManager,
                 mCommonNotifCollection,
                 mNotifPipeline,
                 mSysUiState,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
index b53ad0a..c56fdb1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt
@@ -16,14 +16,12 @@
 
 package com.android.systemui.flags
 
-import android.util.SparseArray
-import android.util.SparseBooleanArray
-import androidx.core.util.containsKey
-
 class FakeFeatureFlags : FeatureFlags {
-    private val booleanFlags = SparseBooleanArray()
-    private val stringFlags = SparseArray<String>()
+    private val booleanFlags = mutableMapOf<Int, Boolean>()
+    private val stringFlags = mutableMapOf<Int, String>()
     private val knownFlagNames = mutableMapOf<Int, String>()
+    private val flagListeners = mutableMapOf<Int, MutableSet<FlagListenable.Listener>>()
+    private val listenerFlagIds = mutableMapOf<FlagListenable.Listener, MutableSet<Int>>()
 
     init {
         Flags.getFlagFields().forEach { field ->
@@ -33,27 +31,52 @@
     }
 
     fun set(flag: BooleanFlag, value: Boolean) {
-        booleanFlags.put(flag.id, value)
+        if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+            notifyFlagChanged(flag)
+        }
     }
 
     fun set(flag: DeviceConfigBooleanFlag, value: Boolean) {
-        booleanFlags.put(flag.id, value)
+        if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+            notifyFlagChanged(flag)
+        }
     }
 
     fun set(flag: ResourceBooleanFlag, value: Boolean) {
-        booleanFlags.put(flag.id, value)
+        if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+            notifyFlagChanged(flag)
+        }
     }
 
     fun set(flag: SysPropBooleanFlag, value: Boolean) {
-        booleanFlags.put(flag.id, value)
+        if (booleanFlags.put(flag.id, value)?.let { value != it } != false) {
+            notifyFlagChanged(flag)
+        }
     }
 
     fun set(flag: StringFlag, value: String) {
-        stringFlags.put(flag.id, value)
+        if (stringFlags.put(flag.id, value)?.let { value != it } == null) {
+            notifyFlagChanged(flag)
+        }
     }
 
     fun set(flag: ResourceStringFlag, value: String) {
-        stringFlags.put(flag.id, value)
+        if (stringFlags.put(flag.id, value)?.let { value != it } == null) {
+            notifyFlagChanged(flag)
+        }
+    }
+
+    private fun notifyFlagChanged(flag: Flag<*>) {
+        flagListeners[flag.id]?.let { listeners ->
+            listeners.forEach { listener ->
+                listener.onFlagChanged(
+                    object : FlagListenable.FlagEvent {
+                        override val flagId = flag.id
+                        override fun requestNoRestart() {}
+                    }
+                )
+            }
+        }
     }
 
     override fun isEnabled(flag: UnreleasedFlag): Boolean = requireBooleanValue(flag.id)
@@ -70,25 +93,30 @@
 
     override fun getString(flag: ResourceStringFlag): String = requireStringValue(flag.id)
 
-    override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {}
+    override fun addListener(flag: Flag<*>, listener: FlagListenable.Listener) {
+        flagListeners.getOrPut(flag.id) { mutableSetOf() }.add(listener)
+        listenerFlagIds.getOrPut(listener) { mutableSetOf() }.add(flag.id)
+    }
 
-    override fun removeListener(listener: FlagListenable.Listener) {}
+    override fun removeListener(listener: FlagListenable.Listener) {
+        listenerFlagIds.remove(listener)?.let {
+                flagIds -> flagIds.forEach {
+                        id -> flagListeners[id]?.remove(listener)
+                }
+        }
+    }
 
     private fun flagName(flagId: Int): String {
         return knownFlagNames[flagId] ?: "UNKNOWN(id=$flagId)"
     }
 
     private fun requireBooleanValue(flagId: Int): Boolean {
-        if (!booleanFlags.containsKey(flagId)) {
-            throw IllegalStateException("Flag ${flagName(flagId)} was accessed but not specified.")
-        }
         return booleanFlags[flagId]
+            ?: error("Flag ${flagName(flagId)} was accessed but not specified.")
     }
 
     private fun requireStringValue(flagId: Int): String {
-        if (!stringFlags.containsKey(flagId)) {
-            throw IllegalStateException("Flag ${flagName(flagId)} was accessed but not specified.")
-        }
         return stringFlags[flagId]
+            ?: error("Flag ${flagName(flagId)} was accessed but not specified.")
     }
 }
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/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 75724bf..487703b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -38,6 +38,7 @@
 import android.view.accessibility.AccessibilityEvent;
 
 import com.android.server.LocalServices;
+import com.android.server.accessibility.cursor.SoftwareCursorGestureHandler;
 import com.android.server.accessibility.gestures.TouchExplorer;
 import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
 import com.android.server.accessibility.magnification.MagnificationGestureHandler;
@@ -141,6 +142,13 @@
      */
     static final int FLAG_SEND_MOTION_EVENTS = 0x00000400;
 
+    /**
+     * Flag for enabling the Software Cursor accessibility feature.
+     *
+     * @see setUserAndEnabledFeatures(int, int)
+     */
+    static final int FLAG_FEATURE_SOFTWARE_CURSOR = 0x00000800;
+
     static final int FEATURES_AFFECTING_MOTION_EVENTS =
             FLAG_FEATURE_INJECT_MOTION_EVENTS
                     | FLAG_FEATURE_AUTOCLICK
@@ -149,7 +157,8 @@
                     | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
                     | FLAG_SERVICE_HANDLES_DOUBLE_TAP
                     | FLAG_REQUEST_MULTI_FINGER_GESTURES
-                    | FLAG_REQUEST_2_FINGER_PASSTHROUGH;
+                    | FLAG_REQUEST_2_FINGER_PASSTHROUGH
+                    | FLAG_FEATURE_SOFTWARE_CURSOR;
 
     private final Context mContext;
 
@@ -170,6 +179,9 @@
 
     private KeyboardInterceptor mKeyboardInterceptor;
 
+    private SparseArray<SoftwareCursorGestureHandler> mSoftwareCursorGestureHandler =
+            new SparseArray<>(0);
+
     private boolean mInstalled;
 
     private int mUserId;
@@ -495,6 +507,16 @@
             mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);
         }
 
+        if ((mEnabledFeatures & FLAG_FEATURE_SOFTWARE_CURSOR) != 0) {
+            // TODO: Add full support for multiple displays.
+            final SoftwareCursorGestureHandler softwareCursorGestureHandler =
+                    new SoftwareCursorGestureHandler(displayContext,
+                        mAms.getSoftwareCursorManager(),
+                        mAms.getTraceManager());
+            addFirstEventHandler(displayId, softwareCursorGestureHandler);
+            mSoftwareCursorGestureHandler.put(displayId, softwareCursorGestureHandler);
+        }
+
         if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
             MotionEventInjector injector = new MotionEventInjector(
                     mContext.getMainLooper(), mAms.getTraceManager());
@@ -565,12 +587,20 @@
             mTouchExplorer.remove(displayId);
         }
 
-        final MagnificationGestureHandler handler = mMagnificationGestureHandler.get(displayId);
+        final MagnificationGestureHandler handler =
+                mMagnificationGestureHandler.get(displayId);
         if (handler != null) {
             handler.onDestroy();
             mMagnificationGestureHandler.remove(displayId);
         }
 
+        final SoftwareCursorGestureHandler softwareCursorHandler =
+                mSoftwareCursorGestureHandler.get(displayId);
+        if (softwareCursorHandler != null) {
+            softwareCursorHandler.onDestroy();
+            mSoftwareCursorGestureHandler.remove(displayId);
+        }
+
         final EventStreamTransformation eventStreamTransformation = mEventHandler.get(displayId);
         if (eventStreamTransformation != null) {
             mEventHandler.remove(displayId);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6a6d2bb..f55cfb1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -139,6 +139,7 @@
 import com.android.server.AccessibilityManagerInternal;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.accessibility.cursor.SoftwareCursorManager;
 import com.android.server.accessibility.magnification.MagnificationController;
 import com.android.server.accessibility.magnification.MagnificationProcessor;
 import com.android.server.accessibility.magnification.MagnificationScaleProvider;
@@ -243,6 +244,8 @@
     private final MagnificationController mMagnificationController;
     private final MagnificationProcessor mMagnificationProcessor;
 
+    private final SoftwareCursorManager mSoftwareCursorManager;
+
     private final MainHandler mMainHandler;
 
     // Lazily initialized - access through getSystemActionPerformer()
@@ -404,6 +407,7 @@
         mMagnificationController = magnificationController;
         mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
         mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
+        mSoftwareCursorManager = new SoftwareCursorManager();
         if (inputFilter != null) {
             mInputFilter = inputFilter;
             mHasInputFilter = true;
@@ -437,6 +441,7 @@
                 new MagnificationScaleProvider(mContext));
         mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
         mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
+        mSoftwareCursorManager = new SoftwareCursorManager();
         init();
     }
 
@@ -683,8 +688,8 @@
                 if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_PACKAGE_BROADCAST_RECEIVER)) {
                     mTraceManager.logTrace(LOG_TAG + ".PM.onHandleForceStop",
                             FLAGS_PACKAGE_BROADCAST_RECEIVER,
-                            "intent=" + intent + ";packages=" + packages + ";uid=" + uid
-                            + ";doit=" + doit);
+                            "intent=" + intent + ";packages=" + Arrays.toString(packages)
+                            + ";uid=" + uid + ";doit=" + doit);
                 }
                 synchronized (mLock) {
                     final int userId = getChangingUserId();
@@ -952,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);
@@ -2281,6 +2287,9 @@
             if (userState.isPerformGesturesEnabledLocked()) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
             }
+            if (userState.isSoftwareCursorEnabledLocked()) {
+                flags |= AccessibilityInputFilter.FLAG_FEATURE_SOFTWARE_CURSOR;
+            }
             if (flags != 0) {
                 if (!mHasInputFilter) {
                     mHasInputFilter = true;
@@ -3482,6 +3491,15 @@
         return mMagnificationController;
     }
 
+    /**
+     * Getter of {@link SoftwareCursorManager}.
+     *
+     * @return SoftwareCursorManager
+     */
+    SoftwareCursorManager getSoftwareCursorManager() {
+        return mSoftwareCursorManager;
+    }
+
     @Override
     public void associateEmbeddedHierarchy(@NonNull IBinder host, @NonNull IBinder embedded) {
         if (mTraceManager.isA11yTracingEnabledForTypes(FLAGS_ACCESSIBILITY_MANAGER)) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
index 55dc196..5366a45 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java
@@ -109,6 +109,7 @@
     private boolean mIsAudioDescriptionByDefaultRequested;
     private boolean mIsAutoclickEnabled;
     private boolean mIsDisplayMagnificationEnabled;
+    private boolean mIsSoftwareCursorEnabled;
     private boolean mIsFilterKeyEventsEnabled;
     private boolean mIsPerformGesturesEnabled;
     private boolean mAccessibilityFocusOnlyInActiveWindow;
@@ -208,6 +209,7 @@
         mRequestTwoFingerPassthrough = false;
         mSendMotionEventsEnabled = false;
         mIsDisplayMagnificationEnabled = false;
+        mIsSoftwareCursorEnabled = false;
         mIsAutoclickEnabled = false;
         mUserNonInteractiveUiTimeout = 0;
         mUserInteractiveUiTimeout = 0;
@@ -509,6 +511,8 @@
         pw.append(", sendMotionEventsEnabled").append(String.valueOf(mSendMotionEventsEnabled));
         pw.append(", displayMagnificationEnabled=").append(String.valueOf(
                 mIsDisplayMagnificationEnabled));
+        pw.append(", softwareCursorEnabled=").append(String.valueOf(
+                mIsSoftwareCursorEnabled));
         pw.append(", autoclickEnabled=").append(String.valueOf(mIsAutoclickEnabled));
         pw.append(", nonInteractiveUiTimeout=").append(String.valueOf(mNonInteractiveUiTimeout));
         pw.append(", interactiveUiTimeout=").append(String.valueOf(mInteractiveUiTimeout));
@@ -619,6 +623,14 @@
         mIsDisplayMagnificationEnabled = enabled;
     }
 
+    public boolean isSoftwareCursorEnabledLocked() {
+        return mIsSoftwareCursorEnabled;
+    }
+
+    public void setSoftwareCursorEnabledLocked(boolean enabled) {
+        mIsSoftwareCursorEnabled = enabled;
+    }
+
     public boolean isFilterKeyEventsEnabledLocked() {
         return mIsFilterKeyEventsEnabled;
     }
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/accessibility/java/com/android/server/accessibility/cursor/SoftwareCursorGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/cursor/SoftwareCursorGestureHandler.java
new file mode 100644
index 0000000..6ffa8f7
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/cursor/SoftwareCursorGestureHandler.java
@@ -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.server.accessibility.cursor;
+
+import android.content.Context;
+import android.util.Log;
+import android.util.Slog;
+import android.view.MotionEvent;
+
+import com.android.server.accessibility.AccessibilityTraceManager;
+import com.android.server.accessibility.BaseEventStreamTransformation;
+
+/**
+ * Handles touch input for the Software Cursor accessibility feature.
+ *
+ * The behavior is as follows:
+ *
+ * <ol>
+ *   <li> 1. Enable Software Cursor by swiping from the trigger zone on the edge of the screen.
+ *   <li> 2. Move the cursor by swiping anywhere on the touch screen. Select by tapping anywhere on
+ *   the touch screen.
+ *   <li> 3. Put the cursor away by swiping it past either edge of the screen.
+ * </ol>
+ *
+ * TODO(b/243552818): Determine how to handle multi-display.
+ */
+public final class SoftwareCursorGestureHandler extends BaseEventStreamTransformation {
+
+
+    private static final String LOG_TAG = "SWCursorGestureHandler";
+    private static final boolean DEBUG_ALL = Log.isLoggable("SWCursorGestureHandler",
+            Log.DEBUG);
+
+    Context mContext;
+    SoftwareCursorManager mSoftwareCursorManager;
+    AccessibilityTraceManager mTraceManager;
+
+    public SoftwareCursorGestureHandler(Context context,
+                          SoftwareCursorManager softwareCursorManager,
+                          AccessibilityTraceManager traceManager) {
+        mContext = context;
+        mSoftwareCursorManager = softwareCursorManager;
+        mTraceManager = traceManager;
+    }
+
+    @Override
+    public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+        if (DEBUG_ALL) {
+            Slog.i(LOG_TAG, "onMotionEvent(" + event + ")");
+        }
+        // TODO: Add logic.
+        // TODO: Prevent users from enabling this filter in conjuntion with TouchExplorer.
+        super.onMotionEvent(event, rawEvent, policyFlags);
+    }
+
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/services/accessibility/java/com/android/server/accessibility/cursor/SoftwareCursorManager.java
similarity index 67%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to services/accessibility/java/com/android/server/accessibility/cursor/SoftwareCursorManager.java
index 88e227b..9b370d8 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/services/accessibility/java/com/android/server/accessibility/cursor/SoftwareCursorManager.java
@@ -14,10 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package com.android.server.accessibility.cursor;
 
-import javax.inject.Qualifier
+/**
+ * Allows the Software Cursor feature to interface with its corresponding code in the SystemUI
+ * process.
+ */
+public final class SoftwareCursorManager {
 
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+    public SoftwareCursorManager() {
+      // TODO: Add behavior in a future CL.
+    }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
index f731c44..d20fa8e 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -447,7 +447,7 @@
         StringBuilder builder = new StringBuilder(super.toString());
         if (getState() != STATE_GESTURE_CANCELED) {
             builder.append(", mBase: ")
-                    .append(mBase.toString())
+                    .append(Arrays.toString(mBase))
                     .append(", mMinPixelsBetweenSamplesX:")
                     .append(mMinPixelsBetweenSamplesX)
                     .append(", mMinPixelsBetweenSamplesY:")
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 01cee33..b5fdaca 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -41,7 +41,12 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
 import android.service.autofill.Dataset;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
@@ -61,7 +66,7 @@
      * Reasons why presentation was not shown. These are wrappers around
      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
      */
-    @IntDef(prefix = { "NOT_SHOWN_REASON" }, value = {
+    @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = {
             NOT_SHOWN_REASON_ANY_SHOWN,
             NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
             NOT_SHOWN_REASON_VIEW_CHANGED,
@@ -72,6 +77,7 @@
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface NotShownReason {}
+
     public static final int NOT_SHOWN_REASON_ANY_SHOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
     public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
     public static final int NOT_SHOWN_REASON_VIEW_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
@@ -172,6 +178,45 @@
         });
     }
 
+    public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
+        mEventInternal.ifPresent(event -> {
+            event.mDisplayPresentationType = UI_TYPE_INLINE;
+            String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
+                    Settings.Secure.DEFAULT_INPUT_METHOD, userId);
+            if (TextUtils.isEmpty(imeString)) {
+                Slog.w(TAG, "No default IME found");
+                return;
+            }
+            ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
+            if (imeComponent == null) {
+                Slog.w(TAG, "No default IME found");
+                return;
+            }
+            int imeUid;
+            String packageName = imeComponent.getPackageName();
+            try {
+                imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
+                        PackageManager.ApplicationInfoFlags.of(0), userId).uid;
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.w(TAG, "Couldn't find packageName: " + packageName);
+                return;
+            }
+            event.mInlineSuggestionHostUid = imeUid;
+        });
+    }
+
+    public void maybeSetAutofillServiceUid(int uid) {
+        mEventInternal.ifPresent(event -> {
+            event.mAutofillServiceUid = uid;
+        });
+    }
+
+    public void maybeSetIsNewRequest(boolean isRequestTriggered) {
+        mEventInternal.ifPresent(event -> {
+            event.mIsRequestTriggered = isRequestTriggered;
+        });
+    }
+
     public void logAndEndEvent() {
         if (!mEventInternal.isPresent()) {
             Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
@@ -190,7 +235,10 @@
                     + " mCountNotShownImePresentationNotDrawn="
                     + event.mCountNotShownImePresentationNotDrawn
                     + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
-                    + " mDisplayPresentationType=" + event.mDisplayPresentationType);
+                    + " mDisplayPresentationType=" + event.mDisplayPresentationType
+                    + " mAutofillServiceUid=" + event.mAutofillServiceUid
+                    + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
+                    + " mIsRequestTriggered=" + event.mIsRequestTriggered);
         }
 
         // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
@@ -208,7 +256,10 @@
                 event.mCountFilteredUserTyping,
                 event.mCountNotShownImePresentationNotDrawn,
                 event.mCountNotShownImeUserNotSeen,
-                event.mDisplayPresentationType);
+                event.mDisplayPresentationType,
+                event.mAutofillServiceUid,
+                event.mInlineSuggestionHostUid,
+                event.mIsRequestTriggered);
         mEventInternal = Optional.empty();
     }
 
@@ -222,6 +273,9 @@
         int mCountNotShownImePresentationNotDrawn;
         int mCountNotShownImeUserNotSeen;
         int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+        int mAutofillServiceUid = -1;
+        int mInlineSuggestionHostUid = -1;
+        boolean mIsRequestTriggered;
 
         PresentationStatsEventInternal() {}
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 1fea539..d5945a5 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -68,6 +68,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ServiceInfo;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -79,6 +80,7 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -3040,6 +3042,7 @@
                     mSessionFlags.mFillDialogDisabled = true;
                 }
                 mPresentationStatsEventLogger.startNewEvent();
+                mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
                 requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
                 break;
             case ACTION_VALUE_CHANGED:
@@ -3129,6 +3132,7 @@
                 }
 
                 mPresentationStatsEventLogger.startNewEvent();
+                mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
                 if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
                     return;
                 }
@@ -3373,7 +3377,8 @@
                     // shown, inflated, and filtered.
                     mPresentationStatsEventLogger.maybeSetCountShown(
                             response.getDatasets(), mCurrentViewId);
-                    mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_INLINE);
+                    mPresentationStatsEventLogger.maybeSetInlinePresentationAndSuggestionHostUid(
+                            mContext, userId);
                     return;
                 }
             }
@@ -4750,4 +4755,9 @@
                 return "UNKNOWN_SESSION_STATE_" + sessionState;
         }
     }
+
+    private int getAutofillServiceUid() {
+        ServiceInfo serviceInfo = mService.getServiceInfo();
+        return serviceInfo == null ? Process.INVALID_UID : serviceInfo.applicationInfo.uid;
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 907daa3..aec5f5e 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2830,7 +2830,7 @@
                                         + " includekeyvalue="
                                         + doKeyValue
                                         + " pkgs="
-                                        + pkgList));
+                                        + Arrays.toString(pkgList)));
             }
             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup..."));
 
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 5dacdb4..d0300ff 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -25,9 +25,9 @@
 import android.annotation.Nullable;
 import android.app.backup.BackupManager.OperationType;
 import android.app.backup.BackupTransport;
+import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
-import android.app.compat.CompatChanges;
 import android.compat.annotation.Overridable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -46,6 +46,7 @@
 
 import com.google.android.collect.Sets;
 
+import java.util.Arrays;
 import java.util.Set;
 
 /**
@@ -360,8 +361,8 @@
         }
 
         if (DEBUG) {
-            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device="
-                    + signingInfo.getApkContentsSigners());
+            Slog.v(TAG, "signaturesMatch(): stored=" + Arrays.toString(storedSigs)
+                    + " device=" + Arrays.toString(signingInfo.getApkContentsSigners()));
         }
 
         final int nStored = storedSigs.length;
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 2acb65e..3814591 100644
--- a/services/companion/java/com/android/server/companion/CompanionApplicationController.java
+++ b/services/companion/java/com/android/server/companion/CompanionApplicationController.java
@@ -31,9 +31,10 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.infra.PerUser;
-import com.android.internal.util.CollectionUtils;
+import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -65,36 +66,26 @@
 @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
 
-    interface Callback {
-        /**
-         * @return {@code true} if should schedule rebinding.
-         *         {@code false} if we do not need to rebind.
-         */
-        boolean onCompanionApplicationBindingDied(
-                @UserIdInt int userId, @NonNull String packageName);
-
-        /**
-         * Callback after timeout for previously scheduled rebind has passed.
-         */
-        void onRebindCompanionApplicationTimeout(
-                @UserIdInt int userId, @NonNull String packageName);
-    }
-
     private final @NonNull Context mContext;
-    private final @NonNull Callback mCallback;
+    private final @NonNull AssociationStore mAssociationStore;
+    private final @NonNull CompanionDevicePresenceMonitor mDevicePresenceMonitor;
     private final @NonNull CompanionServicesRegister mCompanionServicesRegister;
+
     @GuardedBy("mBoundCompanionApplications")
     private final @NonNull AndroidPackageMap<List<CompanionDeviceServiceConnector>>
             mBoundCompanionApplications;
+    @GuardedBy("mScheduledForRebindingCompanionApplications")
     private final @NonNull AndroidPackageMap<Boolean> mScheduledForRebindingCompanionApplications;
 
-    CompanionApplicationController(Context context, Callback callback) {
+    CompanionApplicationController(Context context, AssociationStore associationStore,
+            CompanionDevicePresenceMonitor companionDevicePresenceMonitor) {
         mContext = context;
-        mCallback = callback;
+        mAssociationStore = associationStore;
+        mDevicePresenceMonitor = companionDevicePresenceMonitor;
         mCompanionServicesRegister = new CompanionServicesRegister();
         mBoundCompanionApplications = new AndroidPackageMap<>();
         mScheduledForRebindingCompanionApplications = new AndroidPackageMap<>();
@@ -125,21 +116,26 @@
             return;
         }
 
-        final List<CompanionDeviceServiceConnector> serviceConnectors;
+        final List<CompanionDeviceServiceConnector> serviceConnectors = new ArrayList<>();
         synchronized (mBoundCompanionApplications) {
             if (mBoundCompanionApplications.containsValueForPackage(userId, packageName)) {
                 if (DEBUG) Log.e(TAG, "u" + userId + "/" + packageName + " is ALREADY bound.");
                 return;
             }
 
-            serviceConnectors = CollectionUtils.map(companionServices, componentName ->
-                            CompanionDeviceServiceConnector.newInstance(mContext, userId,
-                                    componentName, isSelfManaged));
+            for (int i = 0; i < companionServices.size(); i++) {
+                boolean isPrimary = i == 0;
+                serviceConnectors.add(CompanionDeviceServiceConnector.newInstance(mContext, userId,
+                        companionServices.get(i), isSelfManaged, isPrimary));
+            }
+
             mBoundCompanionApplications.setValueForPackage(userId, packageName, serviceConnectors);
         }
 
-        // The first connector in the list is always the primary connector: set a listener to it.
-        serviceConnectors.get(0).setListener(this::onPrimaryServiceBindingDied);
+        // Set listeners for both Primary and Secondary connectors.
+        for (CompanionDeviceServiceConnector serviceConnector : serviceConnectors) {
+            serviceConnector.setListener(this::onBinderDied);
+        }
 
         // Now "bind" all the connectors: the primary one and the rest of them.
         for (CompanionDeviceServiceConnector serviceConnector : serviceConnectors) {
@@ -154,9 +150,15 @@
         if (DEBUG) Log.i(TAG, "unbind() u" + userId + "/" + packageName);
 
         final List<CompanionDeviceServiceConnector> serviceConnectors;
+
         synchronized (mBoundCompanionApplications) {
             serviceConnectors = mBoundCompanionApplications.removePackage(userId, packageName);
         }
+
+        synchronized (mScheduledForRebindingCompanionApplications) {
+            mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
+        }
+
         if (serviceConnectors == null) {
             if (DEBUG) {
                 Log.e(TAG, "unbindCompanionApplication(): "
@@ -180,24 +182,59 @@
         }
     }
 
-    private void scheduleRebinding(@UserIdInt int userId, @NonNull String packageName) {
-        mScheduledForRebindingCompanionApplications.setValueForPackage(userId, packageName, true);
+    private void scheduleRebinding(@UserIdInt int userId, @NonNull String packageName,
+            CompanionDeviceServiceConnector serviceConnector) {
+        Slog.i(TAG, "scheduleRebinding() " + userId + "/" + packageName);
 
+        if (isRebindingCompanionApplicationScheduled(userId, packageName)) {
+            if (DEBUG) {
+                Log.i(TAG, "CompanionApplication rebinding has been scheduled, skipping "
+                        + serviceConnector.getComponentName());
+            }
+            return;
+        }
+
+        if (serviceConnector.isPrimary()) {
+            synchronized (mScheduledForRebindingCompanionApplications) {
+                mScheduledForRebindingCompanionApplications.setValueForPackage(
+                        userId, packageName, true);
+            }
+        }
+
+        // Rebinding in 10 seconds.
         Handler.getMain().postDelayed(() ->
-                onRebindingCompanionApplicationTimeout(userId, packageName), REBIND_TIMEOUT);
+                onRebindingCompanionApplicationTimeout(userId, packageName, serviceConnector),
+                REBIND_TIMEOUT);
     }
 
-    boolean isRebindingCompanionApplicationScheduled(
+    private boolean isRebindingCompanionApplicationScheduled(
             @UserIdInt int userId, @NonNull String packageName) {
-        return mScheduledForRebindingCompanionApplications
-                .containsValueForPackage(userId, packageName);
+        synchronized (mScheduledForRebindingCompanionApplications) {
+            return mScheduledForRebindingCompanionApplications.containsValueForPackage(
+                    userId, packageName);
+        }
     }
 
     private void onRebindingCompanionApplicationTimeout(
-            @UserIdInt int userId, @NonNull String packageName) {
-        mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
+            @UserIdInt int userId, @NonNull String packageName,
+            @NonNull CompanionDeviceServiceConnector serviceConnector) {
+        // Re-mark the application is bound.
+        if (serviceConnector.isPrimary()) {
+            synchronized (mBoundCompanionApplications) {
+                if (!mBoundCompanionApplications.containsValueForPackage(userId, packageName)) {
+                    List<CompanionDeviceServiceConnector> serviceConnectors =
+                            Collections.singletonList(serviceConnector);
+                    mBoundCompanionApplications.setValueForPackage(userId, packageName,
+                            serviceConnectors);
+                }
+            }
 
-        mCallback.onRebindCompanionApplicationTimeout(userId, packageName);
+            synchronized (mScheduledForRebindingCompanionApplications) {
+                mScheduledForRebindingCompanionApplications.removePackage(userId, packageName);
+            }
+        }
+
+        serviceConnector.connect();
     }
 
     void notifyCompanionApplicationDeviceAppeared(AssociationInfo association) {
@@ -219,6 +256,9 @@
             return;
         }
 
+        Log.i(TAG, "Calling onDeviceAppeared to userId=[" + userId + "] package=["
+                + packageName + "] associationId=[" + association.getId() + "]");
+
         primaryServiceConnector.postOnDeviceAppeared(association);
     }
 
@@ -241,6 +281,9 @@
             return;
         }
 
+        Log.i(TAG, "Calling onDeviceDisappeared to userId=[" + userId + "] package=["
+                + packageName + "] associationId=[" + association.getId() + "]");
+
         primaryServiceConnector.postOnDeviceDisappeared(association);
     }
 
@@ -266,19 +309,27 @@
         }
     }
 
-    private void onPrimaryServiceBindingDied(@UserIdInt int userId, @NonNull String packageName) {
-        if (DEBUG) Log.i(TAG, "onPrimaryServiceBindingDied() u" + userId + "/" + packageName);
+    /**
+     * Rebinding for Self-Managed secondary services OR Non-Self-Managed services.
+     */
+    private void onBinderDied(@UserIdInt int userId, @NonNull String packageName,
+            @NonNull CompanionDeviceServiceConnector serviceConnector) {
 
-        // First: mark as NOT bound.
+        boolean isPrimary = serviceConnector.isPrimary();
+        Slog.i(TAG, "onBinderDied() u" + userId + "/" + packageName + " isPrimary: " + isPrimary);
+
+        // First: Only mark not BOUND for primary service.
         synchronized (mBoundCompanionApplications) {
-            mBoundCompanionApplications.removePackage(userId, packageName);
+            if (serviceConnector.isPrimary()) {
+                mBoundCompanionApplications.removePackage(userId, packageName);
+            }
         }
 
-        // Second: invoke callback, schedule rebinding if needed.
-        final boolean shouldScheduleRebind =
-                mCallback.onCompanionApplicationBindingDied(userId, packageName);
+        // Second: schedule rebinding if needed.
+        final boolean shouldScheduleRebind = shouldScheduleRebind(userId, packageName, isPrimary);
+
         if (shouldScheduleRebind) {
-            scheduleRebinding(userId, packageName);
+            scheduleRebinding(userId, packageName, serviceConnector);
         }
     }
 
@@ -291,6 +342,37 @@
         return connectors != null ? connectors.get(0) : null;
     }
 
+    private boolean shouldScheduleRebind(int userId, String packageName, boolean isPrimary) {
+        // Make sure do not schedule rebind for the case ServiceConnector still gets callback after
+        // app is uninstalled.
+        boolean stillAssociated = false;
+
+        for (AssociationInfo ai :
+                mAssociationStore.getAssociationsForPackage(userId, packageName)) {
+            final int associationId = ai.getId();
+            stillAssociated = true;
+
+            if (ai.isSelfManaged()) {
+                // Do not rebind if primary one is died for selfManaged application.
+                if (isPrimary
+                        && mDevicePresenceMonitor.isDevicePresent(associationId)) {
+                    mDevicePresenceMonitor.onSelfManagedDeviceReporterBinderDied(associationId);
+                    return false;
+                }
+                // Do not rebind if both primary and secondary services are died for
+                // selfManaged application.
+                if (!isCompanionApplicationBound(userId, packageName)) {
+                    return false;
+                }
+            } else if (ai.isNotifyOnDeviceNearby()) {
+                // Always rebind for non-selfManaged devices.
+                return true;
+            }
+        }
+
+        return stillAssociated;
+    }
+
     private class CompanionServicesRegister extends PerUser<Map<String, List<ComponentName>>> {
         @Override
         public synchronized @NonNull Map<String, List<ComponentName>> forUser(
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 448d70c..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.*/
@@ -233,7 +233,7 @@
         mAssociationRequestsProcessor = new AssociationRequestsProcessor(
                 /* cdmService */this, mAssociationStore);
         mCompanionAppController = new CompanionApplicationController(
-                context, mApplicationControllerCallback);
+                context, mAssociationStore, mDevicePresenceMonitor);
         mTransportManager = new CompanionTransportManager(context);
         mSystemDataTransferProcessor = new SystemDataTransferProcessor(this, mAssociationStore,
                 mSystemDataTransferRequestStore, mTransportManager);
@@ -387,25 +387,6 @@
         mCompanionAppController.unbindCompanionApplication(userId, packageName);
     }
 
-    private boolean onCompanionApplicationBindingDiedInternal(
-            @UserIdInt int userId, @NonNull String packageName) {
-        for (AssociationInfo ai :
-                mAssociationStore.getAssociationsForPackage(userId, packageName)) {
-            final int associationId = ai.getId();
-            if (ai.isSelfManaged()
-                    && mDevicePresenceMonitor.isDevicePresent(associationId)) {
-                mDevicePresenceMonitor.onSelfManagedDeviceReporterBinderDied(associationId);
-            }
-        }
-        // TODO(b/218613015): implement.
-        return false;
-    }
-
-    private void onRebindCompanionApplicationTimeoutInternal(
-            @UserIdInt int userId, @NonNull String packageName) {
-        // TODO(b/218613015): implement.
-    }
-
     /**
      * @return whether the package should be bound (i.e. at least one of the devices associated with
      *         the package is currently present).
@@ -499,6 +480,10 @@
         for (AssociationInfo association : associationsForPackage) {
             mAssociationStore.removeAssociation(association.getId());
         }
+        // Clear role holders
+        for (AssociationInfo association : associationsForPackage) {
+            maybeRemoveRoleHolderForAssociation(association);
+        }
 
         mCompanionAppController.onPackagesChanged(userId);
     }
@@ -1287,19 +1272,6 @@
         }
     };
 
-    private final CompanionApplicationController.Callback mApplicationControllerCallback =
-            new CompanionApplicationController.Callback() {
-        @Override
-        public boolean onCompanionApplicationBindingDied(int userId, @NonNull String packageName) {
-            return onCompanionApplicationBindingDiedInternal(userId, packageName);
-        }
-
-        @Override
-        public void onRebindCompanionApplicationTimeout(int userId, @NonNull String packageName) {
-            onRebindCompanionApplicationTimeoutInternal(userId, packageName);
-        }
-    };
-
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override
         public void onPackageRemoved(String packageName, int uid) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
index a288f7b..93cc611 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceServiceConnector.java
@@ -43,12 +43,13 @@
  */
 @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}  */
     interface Listener {
-        void onBindingDied(@UserIdInt int userId, @NonNull String packageName);
+        void onBindingDied(@UserIdInt int userId, @NonNull String packageName,
+                @NonNull CompanionDeviceServiceConnector serviceConnector);
     }
 
     private final @UserIdInt int mUserId;
@@ -57,6 +58,7 @@
     // installs a listener to the primary ServiceConnector), hence we should always null-check the
     // reference before calling on it.
     private @Nullable Listener mListener;
+    private boolean mIsPrimary;
 
     /**
      * Create a CompanionDeviceServiceConnector instance.
@@ -74,17 +76,20 @@
      * service importance level should be higher than 125.
      */
     static CompanionDeviceServiceConnector newInstance(@NonNull Context context,
-            @UserIdInt int userId, @NonNull ComponentName componentName, boolean isSelfManaged) {
+            @UserIdInt int userId, @NonNull ComponentName componentName, boolean isSelfManaged,
+            boolean isPrimary) {
         final int bindingFlags = isSelfManaged ? BIND_TREAT_LIKE_VISIBLE_FOREGROUND_SERVICE
                 : BIND_ALMOST_PERCEPTIBLE;
-        return new CompanionDeviceServiceConnector(context, userId, componentName, bindingFlags);
+        return new CompanionDeviceServiceConnector(
+                context, userId, componentName, bindingFlags, isPrimary);
     }
 
     private CompanionDeviceServiceConnector(@NonNull Context context, @UserIdInt int userId,
-            @NonNull ComponentName componentName, int bindingFlags) {
+            @NonNull ComponentName componentName, int bindingFlags, boolean isPrimary) {
         super(context, buildIntent(componentName), bindingFlags, userId, null);
         mUserId = userId;
         mComponentName = componentName;
+        mIsPrimary = isPrimary;
     }
 
     void setListener(@Nullable Listener listener) {
@@ -110,6 +115,14 @@
         post(it -> unbind());
     }
 
+    boolean isPrimary() {
+        return mIsPrimary;
+    }
+
+    ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     @Override
     protected void onServiceConnectionStatusChanged(
             @NonNull ICompanionDeviceService service, boolean isConnected) {
@@ -119,16 +132,6 @@
         }
     }
 
-    // This method is only called when app is force-closed via settings,
-    // but does not handle crashes. Binder death should be handled in #binderDied()
-    @Override
-    public void onBindingDied(@NonNull ComponentName name) {
-        // IMPORTANT: call super! this will also invoke binderDied()
-        super.onBindingDied(name);
-
-        if (DEBUG) Log.d(TAG, "onBindingDied() " + mComponentName.toShortString());
-    }
-
     @Override
     public void binderDied() {
         super.binderDied();
@@ -137,7 +140,7 @@
 
         // Handle primary process being killed
         if (mListener != null) {
-            mListener.onBindingDied(mUserId, mComponentName.getPackageName());
+            mListener.onBindingDied(mUserId, mComponentName.getPackageName(), this);
         }
     }
 
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..0bba3c9 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;
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 0ce49d0..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;
@@ -652,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);
@@ -1313,4 +1312,7 @@
      * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
      */
     public abstract @SignatureResult int checkUidSignaturesForAllUsers(int uid1, int uid2);
+
+    public abstract void setPackageStoppedState(@NonNull String packageName, boolean stopped,
+            @UserIdInt int userId);
 }
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/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/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 9455a89..1a8cf0b 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -121,7 +121,7 @@
      * {@link #onUserSwitching(int, int)} as the previous user might have been removed already.
      */
     @GuardedBy("mTargetUsers")
-    private @Nullable TargetUser mCurrentUser;
+    @Nullable private TargetUser mCurrentUser;
 
     SystemServiceManager(Context context) {
         mContext = context;
@@ -335,13 +335,10 @@
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
     }
 
-    private @NonNull TargetUser getTargetUser(@UserIdInt int userId) {
-        final TargetUser targetUser;
+    @Nullable private TargetUser getTargetUser(@UserIdInt int userId) {
         synchronized (mTargetUsers) {
-            targetUser = mTargetUsers.get(userId);
+            return mTargetUsers.get(userId);
         }
-        Preconditions.checkState(targetUser != null, "No TargetUser for " + userId);
-        return targetUser;
     }
 
     private @NonNull TargetUser newTargetUser(@UserIdInt int userId) {
@@ -400,6 +397,7 @@
                 prevUser = mCurrentUser;
             }
             curUser = mCurrentUser = getTargetUser(to);
+            Preconditions.checkState(curUser != null, "No TargetUser for " + to);
             if (DEBUG) {
                 Slog.d(TAG, "Set mCurrentUser to " + mCurrentUser);
             }
@@ -441,16 +439,25 @@
         if (eventFlags == 0) {
             return;
         }
+
+        TargetUser targetUser = getTargetUser(userId);
+        if (targetUser == null) {
+            return;
+        }
+
         onUser(TimingsTraceAndSlog.newAsyncLog(),
                 USER_COMPLETED_EVENT,
                 /* prevUser= */ null,
-                getTargetUser(userId),
+                targetUser,
                 new UserCompletedEventType(eventFlags));
     }
 
     private void onUser(@NonNull String onWhat, @UserIdInt int userId) {
+        TargetUser targetUser = getTargetUser(userId);
+        Preconditions.checkState(targetUser != null, "No TargetUser for " + userId);
+
         onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, /* prevUser= */ null,
-                getTargetUser(userId));
+                targetUser);
     }
 
     private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 4828a54..e81bab1d 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -359,6 +359,11 @@
         SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME, Integer.toString(mode));
     }
 
+    @VisibleForTesting
+    void setStartDreamImmediatelyOnDock(boolean startDreamImmediatelyOnDock) {
+        mStartDreamImmediatelyOnDock = startDreamImmediatelyOnDock;
+    }
+
     @Override
     public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
         mCurrentUser = to.getUserIdentifier();
@@ -1824,7 +1829,8 @@
 
         // If we did not start a dock app, then start dreaming if appropriate.
         if (category != null && !dockAppStarted && (mStartDreamImmediatelyOnDock
-                || mKeyguardManager.isKeyguardLocked())) {
+                || mWindowManager.isKeyguardShowingAndNotOccluded()
+                || !mPowerManager.isInteractive())) {
             Sandman.startDreamWhenDockedIfAppropriate(getContext());
         }
     }
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
index 32dc470..3f1d1fe 100644
--- a/services/core/java/com/android/server/VpnManagerService.java
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -28,6 +28,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
 import android.net.INetd;
 import android.net.IVpnManager;
@@ -775,6 +776,12 @@
     };
 
     private void onUserStarted(int userId) {
+        UserInfo user = mUserManager.getUserInfo(userId);
+        if (user == null) {
+            logw("Started user doesn't exist. UserId: " + userId);
+            return;
+        }
+
         synchronized (mVpns) {
             Vpn userVpn = mVpns.get(userId);
             if (userVpn != null) {
@@ -783,7 +790,8 @@
             }
             userVpn = mDeps.createVpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId);
             mVpns.put(userId, userVpn);
-            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+
+            if (user.isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             }
         }
@@ -898,9 +906,15 @@
     }
 
     private void onUserUnlocked(int userId) {
+        UserInfo user = mUserManager.getUserInfo(userId);
+        if (user == null) {
+            logw("Unlocked user doesn't exist. UserId: " + userId);
+            return;
+        }
+
         synchronized (mVpns) {
             // User present may be sent because of an unlock, which might mean an unlocked keystore.
-            if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+            if (user.isPrimary() && isLockdownVpnEnabled()) {
                 updateLockdownVpn();
             } else {
                 startAlwaysOnVpn(userId);
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/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 2eaf323..04bd869 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -667,6 +667,7 @@
                                     + " Not enabling adbwifi.");
                             Settings.Global.putInt(mContentResolver,
                                     Settings.Global.ADB_WIFI_ENABLED, 0);
+                            return;
                         }
 
                         // Check for network change
@@ -675,6 +676,7 @@
                             Slog.e(TAG, "Unable to get the wifi ap's BSSID. Disabling adbwifi.");
                             Settings.Global.putInt(mContentResolver,
                                     Settings.Global.ADB_WIFI_ENABLED, 0);
+                            return;
                         }
                         synchronized (mAdbConnectionInfo) {
                             if (!bssid.equals(mAdbConnectionInfo.getBSSID())) {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 6aa472f..3b299a2 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -192,6 +192,7 @@
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 
 public final class ActiveServices {
@@ -222,6 +223,11 @@
                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE
                     | ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
 
+    // Keep track of number of foreground services and number of apps that have foreground
+    // services in the device. This field is made to be directly accessed without holding AMS lock.
+    static final AtomicReference<Pair<Integer, Integer>> sNumForegroundServices =
+            new AtomicReference(new Pair<>(0, 0));
+
     // Foreground service is stopped for unknown reason.
     static final int FGS_STOP_REASON_UNKNOWN = 0;
     // Foreground service is stopped by app calling Service.stopForeground().
@@ -456,6 +462,7 @@
         final ArrayList<ServiceRecord> mStartingBackground = new ArrayList<>();
 
         final ArrayMap<String, ActiveForegroundApp> mActiveForegroundApps = new ArrayMap<>();
+
         boolean mActiveForegroundAppsChanged;
 
         static final int MSG_BG_START_TIMEOUT = 1;
@@ -2027,6 +2034,7 @@
                         logFGSStateChangeLocked(r,
                                 FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
                                 0, FGS_STOP_REASON_UNKNOWN);
+                        updateNumForegroundServicesLocked();
                     }
                     // Even if the service is already a FGS, we need to update the notification,
                     // so we need to call it again.
@@ -2118,6 +2126,7 @@
                     mAm.updateLruProcessLocked(r.app, false, null);
                     updateServiceForegroundLocked(r.app.mServices, true);
                 }
+                updateNumForegroundServicesLocked();
             }
         }
     }
@@ -4236,9 +4245,8 @@
 
         // Service is now being launched, its package can't be stopped.
         try {
-            AppGlobals.getPackageManager().setPackageStoppedState(
+            mAm.mPackageManagerInt.setPackageStoppedState(
                     r.packageName, false, r.userId);
-        } catch (RemoteException e) {
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
                     + r.packageName + ": " + e);
@@ -4248,7 +4256,8 @@
         final String procName = r.processName;
         HostingRecord hostingRecord = new HostingRecord(
                 HostingRecord.HOSTING_TYPE_SERVICE, r.instanceName,
-                r.definingPackageName, r.definingUid, r.serviceInfo.processName);
+                r.definingPackageName, r.definingUid, r.serviceInfo.processName,
+                getHostingRecordTriggerType(r));
         ProcessRecord app;
 
         if (!isolated) {
@@ -4358,6 +4367,14 @@
         return null;
     }
 
+    private String getHostingRecordTriggerType(ServiceRecord r) {
+        if (Manifest.permission.BIND_JOB_SERVICE.equals(r.permission)
+                && r.mRecentCallingUid == SYSTEM_UID) {
+            return HostingRecord.TRIGGER_TYPE_JOB;
+        }
+        return HostingRecord.TRIGGER_TYPE_UNKNOWN;
+    }
+
     private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg)
             throws TransactionTooLargeException {
         for (int i=r.bindings.size()-1; i>=0; i--) {
@@ -4828,6 +4845,7 @@
         }
 
         smap.ensureNotStartingBackgroundLocked(r);
+        updateNumForegroundServicesLocked();
     }
 
     private void dropFgsNotificationStateLocked(ServiceRecord r) {
@@ -7032,6 +7050,10 @@
                 fgsStopReasonToString(fgsStopReason));
     }
 
+    private void updateNumForegroundServicesLocked() {
+        sNumForegroundServices.set(mAm.mProcessList.getNumForegroundServices());
+    }
+
     boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
             String callingPackage) {
         return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 13a13f2..5e7d814 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -146,6 +146,7 @@
     static final String KEY_NETWORK_ACCESS_TIMEOUT_MS = "network_access_timeout_ms";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
+    private static final boolean DEFAULT_PRIORITIZE_ALARM_BROADCASTS = true;
     private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
     private static final long DEFAULT_FGSERVICE_MIN_REPORT_TIME = 3*1000;
     private static final long DEFAULT_FGSERVICE_SCREEN_ON_BEFORE_TIME = 1*1000;
@@ -325,6 +326,14 @@
      */
     private static final String KEY_PROCESS_KILL_TIMEOUT = "process_kill_timeout";
 
+    /**
+     * {@code true} to send in-flight alarm broadcasts ahead of non-alarms; {@code false}
+     * to queue alarm broadcasts identically to non-alarms [i.e. the pre-U behavior]; or
+     * {@code null} or empty string in order to fall back to whatever the build-time default
+     * was for the device.
+     */
+    private static final String KEY_PRIORITIZE_ALARM_BROADCASTS = "prioritize_alarm_broadcasts";
+
     private static final String KEY_DEFER_BOOT_COMPLETED_BROADCAST =
             "defer_boot_completed_broadcast";
 
@@ -667,6 +676,12 @@
             DEFAULT_DEFER_BOOT_COMPLETED_BROADCAST;
 
     /**
+     * Whether alarm broadcasts are delivered immediately, or queued along with the rest
+     * of the pending ordered broadcasts.
+     */
+    volatile boolean mPrioritizeAlarmBroadcasts = DEFAULT_PRIORITIZE_ALARM_BROADCASTS;
+
+    /**
      * How long the Context.startForegroundService() grace period is to get around to
      * calling Service.startForeground() before we generate ANR.
      */
@@ -977,6 +992,9 @@
                             case KEY_PROCESS_KILL_TIMEOUT:
                                 updateProcessKillTimeout();
                                 break;
+                            case KEY_PRIORITIZE_ALARM_BROADCASTS:
+                                updatePrioritizeAlarmBroadcasts();
+                                break;
                             case KEY_DEFER_BOOT_COMPLETED_BROADCAST:
                                 updateDeferBootCompletedBroadcast();
                                 break;
@@ -1446,6 +1464,17 @@
         }
     }
 
+    private void updatePrioritizeAlarmBroadcasts() {
+        // Flag value can be something that evaluates to `true` or `false`,
+        // or empty/null.  If it's empty/null, the platform default is used.
+        final String flag = DeviceConfig.getString(
+                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                KEY_PRIORITIZE_ALARM_BROADCASTS,
+                "");
+        mPrioritizeAlarmBroadcasts = TextUtils.isEmpty(flag)
+                ? DEFAULT_PRIORITIZE_ALARM_BROADCASTS
+                : Boolean.parseBoolean(flag);
+    }
     private void updateDeferBootCompletedBroadcast() {
         mDeferBootCompletedBroadcast = DeviceConfig.getInt(
                 DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1786,6 +1815,8 @@
         pw.print("="); pw.println(mComponentAliasOverrides);
         pw.print("  "); pw.print(KEY_DEFER_BOOT_COMPLETED_BROADCAST);
         pw.print("="); pw.println(mDeferBootCompletedBroadcast);
+        pw.print("  "); pw.print(KEY_PRIORITIZE_ALARM_BROADCASTS);
+        pw.print("="); pw.println(mPrioritizeAlarmBroadcasts);
         pw.print("  "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_UNTIL_BOOT_COMPLETED);
         pw.print("="); pw.println(mNoKillCachedProcessesUntilBootCompleted);
         pw.print("  "); pw.print(KEY_NO_KILL_CACHED_PROCESSES_POST_BOOT_COMPLETED_DURATION_MILLIS);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7e497fd..2ccba56 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -149,6 +149,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
 import static com.android.server.wm.ActivityTaskManagerService.DUMP_STARTER_CMD;
 import static com.android.server.wm.ActivityTaskManagerService.DUMP_TOP_RESUMED_ACTIVITY;
+import static com.android.server.wm.ActivityTaskManagerService.DUMP_VISIBLE_ACTIVITIES;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
 
@@ -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;
@@ -671,7 +673,7 @@
     final BroadcastQueue mFgOffloadBroadcastQueue;
     // Convenient for easy iteration over the queues. Foreground is first
     // so that dispatch of foreground broadcasts gets precedence.
-    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[4];
+    final BroadcastQueue[] mBroadcastQueues;
 
     @GuardedBy("this")
     BroadcastStats mLastBroadcastStats;
@@ -682,25 +684,33 @@
     TraceErrorLogger mTraceErrorLogger;
 
     BroadcastQueue broadcastQueueForIntent(Intent intent) {
-        if (isOnFgOffloadQueue(intent.getFlags())) {
+        return broadcastQueueForFlags(intent.getFlags(), intent);
+    }
+
+    BroadcastQueue broadcastQueueForFlags(int flags) {
+        return broadcastQueueForFlags(flags, null);
+    }
+
+    BroadcastQueue broadcastQueueForFlags(int flags, Object cookie) {
+        if (isOnFgOffloadQueue(flags)) {
             if (DEBUG_BROADCAST_BACKGROUND) {
                 Slog.i(TAG_BROADCAST,
-                        "Broadcast intent " + intent + " on foreground offload queue");
+                        "Broadcast intent " + cookie + " on foreground offload queue");
             }
             return mFgOffloadBroadcastQueue;
         }
 
-        if (isOnBgOffloadQueue(intent.getFlags())) {
+        if (isOnBgOffloadQueue(flags)) {
             if (DEBUG_BROADCAST_BACKGROUND) {
                 Slog.i(TAG_BROADCAST,
-                        "Broadcast intent " + intent + " on background offload queue");
+                        "Broadcast intent " + cookie + " on background offload queue");
             }
             return mBgOffloadBroadcastQueue;
         }
 
-        final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
+        final boolean isFg = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
         if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
-                "Broadcast intent " + intent + " on "
+                "Broadcast intent " + cookie + " on "
                 + (isFg ? "foreground" : "background") + " queue");
         return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
     }
@@ -2335,7 +2345,7 @@
         mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, handlerThread);
 
         mIntentFirewall = null;
-        mProcessStats = null;
+        mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
         mCpHelper = new ContentProviderHelper(this, false);
         mServices = null;
         mSystemThread = null;
@@ -2355,6 +2365,7 @@
         mPendingStartActivityUids = new PendingStartActivityUids();
         mUseFifoUiScheduling = false;
         mEnableOffloadQueue = false;
+        mBroadcastQueues = new BroadcastQueue[0];
         mFgBroadcastQueue = mBgBroadcastQueue = mBgOffloadBroadcastQueue =
                 mFgOffloadBroadcastQueue = null;
         mComponentAliasResolver = new ComponentAliasResolver(this);
@@ -2413,14 +2424,15 @@
         mEnableOffloadQueue = SystemProperties.getBoolean(
                 "persist.device_config.activity_manager_native_boot.offload_queue_enabled", true);
 
+        mBroadcastQueues = new BroadcastQueue[4];
         mFgBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
-                "foreground", foreConstants, false);
+                "foreground", foreConstants, false, ProcessList.SCHED_GROUP_DEFAULT);
         mBgBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
-                "background", backConstants, true);
+                "background", backConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
         mBgOffloadBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
-                "offload_bg", offloadConstants, true);
+                "offload_bg", offloadConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
         mFgOffloadBroadcastQueue = new BroadcastQueueImpl(this, mHandler,
-                "offload_fg", foreConstants, true);
+                "offload_fg", foreConstants, true, ProcessList.SCHED_GROUP_BACKGROUND);
         mBroadcastQueues[0] = mFgBroadcastQueue;
         mBroadcastQueues[1] = mBgBroadcastQueue;
         mBroadcastQueues[2] = mBgOffloadBroadcastQueue;
@@ -3265,13 +3277,20 @@
         if (thread == null) {
             return null;
         }
+        return getRecordForAppLOSP(thread.asBinder());
+    }
 
-        ProcessRecord record = mProcessList.getLRURecordForAppLOSP(thread);
+    @GuardedBy(anyOf = {"this", "mProcLock"})
+    ProcessRecord getRecordForAppLOSP(IBinder threadBinder) {
+        if (threadBinder == null) {
+            return null;
+        }
+
+        ProcessRecord record = mProcessList.getLRURecordForAppLOSP(threadBinder);
         if (record != null) return record;
 
         // Validation: if it isn't in the LRU list, it shouldn't exist, but let's
         // double-check that.
-        final IBinder threadBinder = thread.asBinder();
         final ArrayMap<String, SparseArray<ProcessRecord>> pmap =
                 mProcessList.getProcessNamesLOSP().getMap();
         for (int i = pmap.size()-1; i >= 0; i--) {
@@ -6739,9 +6758,8 @@
         // TODO: how set package stopped state should work for sdk sandboxes?
         if (!isSdkSandbox) {
             try {
-                AppGlobals.getPackageManager().setPackageStoppedState(
+                mPackageManagerInt.setPackageStoppedState(
                         info.packageName, false, UserHandle.getUserId(app.uid));
-            } catch (RemoteException e) {
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Failed trying to unstop package "
                         + info.packageName + ": " + e);
@@ -8751,12 +8769,40 @@
             if (process.info.isInstantApp()) {
                 sb.append("Instant-App: true\n");
             }
+
             if (isSdkSandboxUid(process.uid)) {
+                final int appUid = Process.getAppUidForSdkSandboxUid(process.uid);
+                try {
+                    String[] clientPackages = pm.getPackagesForUid(appUid);
+                    // In shared UID case, don't add the package information
+                    if (clientPackages.length == 1) {
+                        appendSdkSandboxClientPackageHeader(sb, clientPackages[0], callingUserId);
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error getting packages for client app uid: " + appUid, e);
+                }
                 sb.append("SdkSandbox: true\n");
             }
         }
     }
 
+    private void appendSdkSandboxClientPackageHeader(StringBuilder sb, String pkg, int userId) {
+        final IPackageManager pm = AppGlobals.getPackageManager();
+        sb.append("SdkSandbox-Client-Package: ").append(pkg);
+        try {
+            final PackageInfo pi = pm.getPackageInfo(pkg, 0, userId);
+            if (pi != null) {
+                sb.append(" v").append(pi.getLongVersionCode());
+                if (pi.versionName != null) {
+                    sb.append(" (").append(pi.versionName).append(")");
+                }
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error getting package info for SDK sandbox client: " + pkg, e);
+        }
+        sb.append("\n");
+    }
+
     private static String processClass(ProcessRecord process) {
         if (process == null || process.getPid() == MY_PID) {
             return "system_server";
@@ -9530,7 +9576,8 @@
                     || DUMP_LASTANR_CMD.equals(cmd) || DUMP_LASTANR_TRACES_CMD.equals(cmd)
                     || DUMP_STARTER_CMD.equals(cmd) || DUMP_CONTAINERS_CMD.equals(cmd)
                     || DUMP_RECENTS_CMD.equals(cmd) || DUMP_RECENTS_SHORT_CMD.equals(cmd)
-                    || DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)) {
+                    || DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)
+                    || DUMP_VISIBLE_ACTIVITIES.equals(cmd)) {
                 mAtmInternal.dump(
                         cmd, fd, pw, args, opti, true /* dumpAll */, dumpClient, dumpPackage);
             } else if ("binder-proxies".equals(cmd)) {
@@ -10624,7 +10671,7 @@
         if (!onlyHistory && !onlyReceivers && dumpAll) {
             pw.println();
             for (BroadcastQueue queue : mBroadcastQueues) {
-                pw.println("  Queue " + queue.toString() + ": " + queue.describeState());
+                pw.println("  Queue " + queue.toString() + ": " + queue.describeStateLocked());
             }
             pw.println("  mHandler:");
             mHandler.dump(new PrintWriterPrinter(pw), "    ");
@@ -12909,9 +12956,8 @@
             // !!! TODO: currently no check here that we're already bound
             // Backup agent is now in use, its package can't be stopped.
             try {
-                AppGlobals.getPackageManager().setPackageStoppedState(
+                mPackageManagerInt.setPackageStoppedState(
                         app.packageName, false, UserHandle.getUserId(app.uid));
-            } catch (RemoteException e) {
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Failed trying to unstop package "
                         + app.packageName + ": " + e);
@@ -13392,20 +13438,18 @@
         final long origId = Binder.clearCallingIdentity();
         try {
             boolean doTrim = false;
-
             synchronized(this) {
                 ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                 if (rl != null) {
                     final BroadcastRecord r = rl.curBroadcast;
-                    if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
+                    if (r != null) {
                         final boolean doNext = r.queue.finishReceiverLocked(
-                                r, r.resultCode, r.resultData, r.resultExtras,
+                                rl.app, r.resultCode, r.resultData, r.resultExtras,
                                 r.resultAbort, false);
                         if (doNext) {
                             doTrim = true;
                         }
                     }
-
                     if (rl.app != null) {
                         rl.app.mReceivers.removeReceiver(rl);
                     }
@@ -14572,9 +14616,9 @@
         }
     }
 
-    public void finishReceiver(IBinder who, int resultCode, String resultData,
+    public void finishReceiver(IBinder caller, int resultCode, String resultData,
             Bundle resultExtras, boolean resultAbort, int flags) {
-        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
+        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + caller);
 
         // Refuse possible leaked file descriptors
         if (resultExtras != null && resultExtras.hasFileDescriptors()) {
@@ -14583,25 +14627,16 @@
 
         final long origId = Binder.clearCallingIdentity();
         try {
-            boolean doNext = false;
-            BroadcastRecord r;
-            BroadcastQueue queue;
-
             synchronized(this) {
-                if (isOnFgOffloadQueue(flags)) {
-                    queue = mFgOffloadBroadcastQueue;
-                } else if (isOnBgOffloadQueue(flags)) {
-                    queue = mBgOffloadBroadcastQueue;
-                } else {
-                    queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
-                            ? mFgBroadcastQueue : mBgBroadcastQueue;
+                final ProcessRecord callerApp = getRecordForAppLOSP(caller);
+                if (callerApp == null) {
+                    Slog.w(TAG, "finishReceiver: no app for " + caller);
+                    return;
                 }
 
-                r = queue.getMatchingOrderedReceiver(who);
-                if (r != null) {
-                    doNext = r.queue.finishReceiverLocked(r, resultCode,
+                final BroadcastQueue queue = broadcastQueueForFlags(flags);
+                queue.finishReceiverLocked(callerApp, resultCode,
                         resultData, resultExtras, resultAbort, true);
-                }
                 // updateOomAdjLocked() will be done here
                 trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
             }
@@ -15152,30 +15187,13 @@
     // LIFETIME MANAGEMENT
     // =========================================================
 
-    // Returns whether the app is receiving broadcast.
-    // If receiving, fetch all broadcast queues which the app is
-    // the current [or imminent] receiver on.
-    boolean isReceivingBroadcastLocked(ProcessRecord app,
-            ArraySet<BroadcastQueue> receivingQueues) {
-        final ProcessReceiverRecord prr = app.mReceivers;
-        final int numOfReceivers = prr.numberOfCurReceivers();
-        if (numOfReceivers > 0) {
-            for (int i = 0; i < numOfReceivers; i++) {
-                receivingQueues.add(prr.getCurReceiverAt(i).queue);
-            }
-            return true;
-        }
-
-        // It's not the current receiver, but it might be starting up to become one
+    boolean isReceivingBroadcastLocked(ProcessRecord app, int[] outSchedGroup) {
+        int res = ProcessList.SCHED_GROUP_UNDEFINED;
         for (BroadcastQueue queue : mBroadcastQueues) {
-            final BroadcastRecord r = queue.getPendingBroadcastLocked();
-            if (r != null && r.curApp == app) {
-                // found it; report which queue it's in
-                receivingQueues.add(queue);
-            }
+            res = Math.max(res, queue.getPreferredSchedulingGroupLocked(app));
         }
-
-        return !receivingQueues.isEmpty();
+        outSchedGroup[0] = res;
+        return res != ProcessList.SCHED_GROUP_UNDEFINED;
     }
 
     Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
@@ -15283,7 +15301,7 @@
     @GuardedBy("this")
     final boolean canGcNowLocked() {
         for (BroadcastQueue q : mBroadcastQueues) {
-            if (!q.isIdle()) {
+            if (!q.isIdleLocked()) {
                 return false;
             }
         }
@@ -16195,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);
     }
 
     /**
@@ -17860,35 +17877,19 @@
 
     public void waitForBroadcastIdle(@Nullable PrintWriter pw) {
         enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
-        while (true) {
-            boolean idle = true;
-            synchronized (this) {
-                for (BroadcastQueue queue : mBroadcastQueues) {
-                    if (!queue.isIdle()) {
-                        final String msg = "Waiting for queue " + queue + " to become idle...";
-                        if (pw != null) {
-                            pw.println(msg);
-                            pw.println(queue.describeState());
-                            pw.flush();
-                        }
-                        Slog.v(TAG, msg);
-                        queue.flush();
-                        idle = false;
-                    }
-                }
-            }
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.waitForIdle(pw);
+        }
+        if (pw != null) {
+            pw.println("All broadcast queues are idle!");
+            pw.flush();
+        }
+    }
 
-            if (idle) {
-                final String msg = "All broadcast queues are idle!";
-                if (pw != null) {
-                    pw.println(msg);
-                    pw.flush();
-                }
-                Slog.v(TAG, msg);
-                return;
-            } else {
-                SystemClock.sleep(1000);
-            }
+    public void waitForBroadcastBarrier(@Nullable PrintWriter pw) {
+        enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()");
+        for (BroadcastQueue queue : mBroadcastQueues) {
+            queue.waitForBarrier(pw);
         }
     }
 
@@ -17949,6 +17950,14 @@
     }
 
     /**
+     * Reset the dropbox rate limiter here and in BootReceiver
+     */
+    void resetDropboxRateLimiter() {
+        mDropboxRateLimiter.reset();
+        BootReceiver.resetDropboxRateLimiter();
+    }
+
+    /**
      * Kill processes for the user with id userId and that depend on the package named packageName
      */
     @Override
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 36908ce..b4f6e35 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -341,6 +341,8 @@
                     return runNoHomeScreen(pw);
                 case "wait-for-broadcast-idle":
                     return runWaitForBroadcastIdle(pw);
+                case "wait-for-broadcast-barrier":
+                    return runWaitForBroadcastBarrier(pw);
                 case "compat":
                     return runCompat(pw);
                 case "refresh-settings-cache":
@@ -363,6 +365,8 @@
                     return runGetBgRestrictionLevel(pw);
                 case "observe-foreground-process":
                     return runGetCurrentForegroundProcess(pw, mInternal, mTaskInterface);
+                case "reset-dropbox-rate-limiter":
+                    return runResetDropboxRateLimiter();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -3110,6 +3114,11 @@
         return 0;
     }
 
+    int runWaitForBroadcastBarrier(PrintWriter pw) throws RemoteException {
+        mInternal.waitForBroadcastBarrier(pw);
+        return 0;
+    }
+
     int runRefreshSettingsCache() throws RemoteException {
         mInternal.refreshSettingsCache();
         return 0;
@@ -3577,6 +3586,11 @@
         return 0;
     }
 
+    int runResetDropboxRateLimiter() throws RemoteException {
+        mInternal.resetDropboxRateLimiter();
+        return 0;
+    }
+
     private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
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/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index e9a36e0..4c44343 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -181,7 +181,7 @@
                 for (int i = 0; i < numEntries; i++) {
                     if (recipientUid == mDeferredBroadcasts.get(i).uid) {
                         Deferrals d = mDeferredBroadcasts.remove(i);
-                        mAlarmBroadcasts.add(d);
+                        mAlarmDeferrals.add(d);
                         break;
                     }
                 }
@@ -201,10 +201,10 @@
 
                 // No longer an alarm target, so resume ordinary deferral policy
                 if (newCount <= 0) {
-                    final int numEntries = mAlarmBroadcasts.size();
+                    final int numEntries = mAlarmDeferrals.size();
                     for (int i = 0; i < numEntries; i++) {
-                        if (recipientUid == mAlarmBroadcasts.get(i).uid) {
-                            Deferrals d = mAlarmBroadcasts.remove(i);
+                        if (recipientUid == mAlarmDeferrals.get(i).uid) {
+                            Deferrals d = mAlarmDeferrals.remove(i);
                             insertLocked(mDeferredBroadcasts, d);
                             break;
                         }
@@ -234,7 +234,13 @@
     // General deferrals not holding up alarms
     private final ArrayList<Deferrals> mDeferredBroadcasts = new ArrayList<>();
     // Deferrals that *are* holding up alarms; ordered by alarm dispatch time
-    private final ArrayList<Deferrals> mAlarmBroadcasts = new ArrayList<>();
+    private final ArrayList<Deferrals> mAlarmDeferrals = new ArrayList<>();
+    // Under the "deliver alarm broadcasts immediately" policy, the queue of
+    // upcoming alarm broadcasts.  These are always delivered first - if the
+    // policy is changed on the fly from immediate-alarm-delivery to the previous
+    // in-order-queueing behavior, pending immediate alarm deliveries will drain
+    // and then the behavior settle into the pre-U semantics.
+    private final ArrayList<BroadcastRecord> mAlarmQueue = new ArrayList<>();
 
     // Next outbound broadcast, established by getNextBroadcastLocked()
     private BroadcastRecord mCurrentBroadcast;
@@ -528,8 +534,9 @@
         synchronized (mLock) {
             return mCurrentBroadcast == null
                     && mOrderedBroadcasts.isEmpty()
+                    && mAlarmQueue.isEmpty()
                     && isDeferralsListEmpty(mDeferredBroadcasts)
-                    && isDeferralsListEmpty(mAlarmBroadcasts);
+                    && isDeferralsListEmpty(mAlarmDeferrals);
         }
     }
 
@@ -557,7 +564,13 @@
         }
         sb.append(mOrderedBroadcasts.size());
         sb.append(" ordered");
-        int n = pendingInDeferralsList(mAlarmBroadcasts);
+        int n = mAlarmQueue.size();
+        if (n > 0) {
+            sb.append(", ");
+            sb.append(n);
+            sb.append(" alarms");
+        }
+        n = pendingInDeferralsList(mAlarmDeferrals);
         if (n > 0) {
             sb.append(", ");
             sb.append(n);
@@ -592,8 +605,16 @@
     // ----------------------------------
     // BroadcastQueue operation support
     void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+        final ArrayList<BroadcastRecord> queue =
+                (r.alarm && mQueue.mService.mConstants.mPrioritizeAlarmBroadcasts)
+                        ? mAlarmQueue
+                        : mOrderedBroadcasts;
+
         if (r.receivers == null || r.receivers.isEmpty()) {
-            mOrderedBroadcasts.add(r);
+            // Fast no-op path for broadcasts that won't actually be dispatched to
+            // receivers - we still need to handle completion callbacks and historical
+            // records, but we don't need to consider the fancy cases.
+            queue.add(r);
             return;
         }
 
@@ -622,7 +643,8 @@
                 return;
             }
         } else {
-            mOrderedBroadcasts.add(r);
+            // Ordinary broadcast, so put it on the appropriate queue and carry on
+            queue.add(r);
         }
     }
 
@@ -652,10 +674,13 @@
     BroadcastRecord replaceBroadcastLocked(BroadcastRecord r, String typeForLogging) {
         // Simple case, in the ordinary queue.
         BroadcastRecord old = replaceBroadcastLocked(mOrderedBroadcasts, r, typeForLogging);
-
+        // ... or possibly in the simple alarm queue
+        if (old == null) {
+            old = replaceBroadcastLocked(mAlarmQueue, r, typeForLogging);
+        }
         // If we didn't find it, less-simple:  in a deferral queue?
         if (old == null) {
-            old = replaceDeferredBroadcastLocked(mAlarmBroadcasts, r, typeForLogging);
+            old = replaceDeferredBroadcastLocked(mAlarmDeferrals, r, typeForLogging);
         }
         if (old == null) {
             old = replaceDeferredBroadcastLocked(mDeferredBroadcasts, r, typeForLogging);
@@ -706,6 +731,10 @@
         boolean didSomething = cleanupBroadcastListDisabledReceiversLocked(mOrderedBroadcasts,
                 packageName, filterByClasses, userId, doit);
         if (doit || !didSomething) {
+            didSomething = cleanupBroadcastListDisabledReceiversLocked(mAlarmQueue,
+                    packageName, filterByClasses, userId, doit);
+        }
+        if (doit || !didSomething) {
             ArrayList<BroadcastRecord> lockedBootCompletedBroadcasts = new ArrayList<>();
             for (int u = 0, usize = mUser2Deferred.size(); u < usize; u++) {
                 SparseArray<BroadcastRecord> brs =
@@ -731,7 +760,7 @@
                     packageName, filterByClasses, userId, doit);
         }
         if (doit || !didSomething) {
-            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmBroadcasts,
+            didSomething |= cleanupDeferralsListDisabledReceiversLocked(mAlarmDeferrals,
                     packageName, filterByClasses, userId, doit);
         }
         if (doit || !didSomething) {
@@ -781,12 +810,15 @@
         if (mCurrentBroadcast != null) {
             mCurrentBroadcast.dumpDebug(proto, fieldId);
         }
-        for (Deferrals d : mAlarmBroadcasts) {
+        for (Deferrals d : mAlarmDeferrals) {
             d.dumpDebug(proto, fieldId);
         }
         for (BroadcastRecord br : mOrderedBroadcasts) {
             br.dumpDebug(proto, fieldId);
         }
+        for (BroadcastRecord br : mAlarmQueue) {
+            br.dumpDebug(proto, fieldId);
+        }
         for (Deferrals d : mDeferredBroadcasts) {
             d.dumpDebug(proto, fieldId);
         }
@@ -816,23 +848,33 @@
             return mCurrentBroadcast;
         }
 
-        final boolean someQueued = !mOrderedBroadcasts.isEmpty();
-
         BroadcastRecord next = null;
 
+        // Alarms in flight take precedence over everything else.  This queue
+        // will be non-empty only when the relevant policy is in force, but if
+        // policy has changed on the fly we still need to drain this before we
+        // settle into the legacy behavior.
+        if (!mAlarmQueue.isEmpty()) {
+            next = mAlarmQueue.remove(0);
+        }
+
+        // Next in precedence are deferred BOOT_COMPLETED broadcasts
         if (next == null) {
             next = dequeueDeferredBootCompletedBroadcast();
         }
 
-        if (next == null && !mAlarmBroadcasts.isEmpty()) {
-            next = popLocked(mAlarmBroadcasts);
+        // Alarm-related deferrals are next in precedence...
+        if (next == null && !mAlarmDeferrals.isEmpty()) {
+            next = popLocked(mAlarmDeferrals);
             if (DEBUG_BROADCAST_DEFERRAL && next != null) {
                 Slog.i(TAG, "Next broadcast from alarm targets: " + next);
             }
         }
 
+        final boolean someQueued = !mOrderedBroadcasts.isEmpty();
+
         if (next == null && !mDeferredBroadcasts.isEmpty()) {
-            // We're going to deliver either:
+            // A this point we're going to deliver either:
             // 1. the next "overdue" deferral; or
             // 2. the next ordinary ordered broadcast; *or*
             // 3. the next not-yet-overdue deferral.
@@ -937,7 +979,7 @@
                     scheduleDeferralCheckLocked(true);
                 } else {
                     // alarm-related: strict order-encountered
-                    mAlarmBroadcasts.add(d);
+                    mAlarmDeferrals.add(d);
                 }
             } else {
                 // We're already deferring, but something was slow again.  Reset the
@@ -999,7 +1041,7 @@
      * immediately deliverable.  Used by the wait-for-broadcast-idle mechanism.
      */
     public void cancelDeferralsLocked() {
-        zeroDeferralTimes(mAlarmBroadcasts);
+        zeroDeferralTimes(mAlarmDeferrals);
         zeroDeferralTimes(mDeferredBroadcasts);
     }
 
@@ -1023,7 +1065,7 @@
         Deferrals d = findUidLocked(uid, mDeferredBroadcasts);
         // ...but if not there, also check alarm-prioritized deferrals
         if (d == null) {
-            d = findUidLocked(uid, mAlarmBroadcasts);
+            d = findUidLocked(uid, mAlarmDeferrals);
         }
         return d;
     }
@@ -1035,7 +1077,7 @@
     private boolean removeDeferral(Deferrals d) {
         boolean didRemove = mDeferredBroadcasts.remove(d);
         if (!didRemove) {
-            didRemove = mAlarmBroadcasts.remove(d);
+            didRemove = mAlarmDeferrals.remove(d);
         }
         return didRemove;
     }
@@ -1103,14 +1145,20 @@
         } else {
             pw.println("  (null)");
         }
+        printed |= dumper.didPrint();
 
-        dumper.setHeading("Active ordered broadcasts");
-        dumper.setLabel("Active Ordered Broadcast");
-        for (Deferrals d : mAlarmBroadcasts) {
-            d.dumpLocked(dumper);
+        dumper.setHeading("Active alarm broadcasts");
+        dumper.setLabel("Active Alarm Broadcast");
+        for (BroadcastRecord br : mAlarmQueue) {
+            dumper.dump(br);
         }
         printed |= dumper.didPrint();
 
+        dumper.setHeading("Active ordered broadcasts");
+        dumper.setLabel("Active Ordered Broadcast");
+        for (Deferrals d : mAlarmDeferrals) {
+            d.dumpLocked(dumper);
+        }
         for (BroadcastRecord br : mOrderedBroadcasts) {
             dumper.dump(br);
         }
diff --git a/services/core/java/com/android/server/am/BroadcastHistory.java b/services/core/java/com/android/server/am/BroadcastHistory.java
new file mode 100644
index 0000000..d820d6c
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastHistory.java
@@ -0,0 +1,224 @@
+/*
+ * 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.am;
+
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.TimeUtils;
+import android.util.proto.ProtoOutputStream;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Collection of recent historical broadcasts that are available to be dumped
+ * for debugging purposes. Automatically trims itself over time.
+ */
+public class BroadcastHistory {
+    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
+    static final int MAX_BROADCAST_SUMMARY_HISTORY
+            = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
+
+    /**
+     * Historical data of past broadcasts, for debugging.  This is a ring buffer
+     * whose last element is at mHistoryNext.
+     */
+    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+    int mHistoryNext = 0;
+
+    /**
+     * Summary of historical data of past broadcasts, for debugging.  This is a
+     * ring buffer whose last element is at mSummaryHistoryNext.
+     */
+    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
+    int mSummaryHistoryNext = 0;
+
+    /**
+     * Various milestone timestamps of entries in the mBroadcastSummaryHistory ring
+     * buffer, also tracked via the mSummaryHistoryNext index.  These are all in wall
+     * clock time, not elapsed.
+     */
+    final long[] mSummaryHistoryEnqueueTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
+    final long[] mSummaryHistoryDispatchTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
+    final long[] mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY];
+
+    public void addBroadcastToHistoryLocked(BroadcastRecord original) {
+        // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
+        // So don't change the incoming record directly.
+        final BroadcastRecord historyRecord = original.maybeStripForHistory();
+
+        mBroadcastHistory[mHistoryNext] = historyRecord;
+        mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
+
+        mBroadcastSummaryHistory[mSummaryHistoryNext] = historyRecord.intent;
+        mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = historyRecord.enqueueClockTime;
+        mSummaryHistoryDispatchTime[mSummaryHistoryNext] = historyRecord.dispatchClockTime;
+        mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
+        mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
+    }
+
+    private final int ringAdvance(int x, final int increment, final int ringSize) {
+        x += increment;
+        if (x < 0) return (ringSize - 1);
+        else if (x >= ringSize) return 0;
+        else return x;
+    }
+
+    public void dumpDebug(ProtoOutputStream proto) {
+        int lastIndex = mHistoryNext;
+        int ringIndex = lastIndex;
+        do {
+            // increasing index = more recent entry, and we want to print the most
+            // recent first and work backwards, so we roll through the ring backwards.
+            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
+            BroadcastRecord r = mBroadcastHistory[ringIndex];
+            if (r != null) {
+                r.dumpDebug(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
+            }
+        } while (ringIndex != lastIndex);
+
+        lastIndex = ringIndex = mSummaryHistoryNext;
+        do {
+            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+            Intent intent = mBroadcastSummaryHistory[ringIndex];
+            if (intent == null) {
+                continue;
+            }
+            long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
+            intent.dumpDebug(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
+                    false, true, true, false);
+            proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
+                    mSummaryHistoryEnqueueTime[ringIndex]);
+            proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS,
+                    mSummaryHistoryDispatchTime[ringIndex]);
+            proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS,
+                    mSummaryHistoryFinishTime[ringIndex]);
+            proto.end(summaryToken);
+        } while (ringIndex != lastIndex);
+    }
+
+    public boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName,
+            SimpleDateFormat sdf, boolean dumpAll, boolean needSep) {
+        int i;
+        boolean printed = false;
+
+        i = -1;
+        int lastIndex = mHistoryNext;
+        int ringIndex = lastIndex;
+        do {
+            // increasing index = more recent entry, and we want to print the most
+            // recent first and work backwards, so we roll through the ring backwards.
+            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
+            BroadcastRecord r = mBroadcastHistory[ringIndex];
+            if (r == null) {
+                continue;
+            }
+
+            i++; // genuine record of some sort even if we're filtering it out
+            if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+                continue;
+            }
+            if (!printed) {
+                if (needSep) {
+                    pw.println();
+                }
+                needSep = true;
+                pw.println("  Historical broadcasts [" + queueName + "]:");
+                printed = true;
+            }
+            if (dumpAll) {
+                pw.print("  Historical Broadcast " + queueName + " #");
+                        pw.print(i); pw.println(":");
+                r.dump(pw, "    ", sdf);
+            } else {
+                pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
+                pw.print("    ");
+                pw.println(r.intent.toShortString(false, true, true, false));
+                if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
+                    pw.print("    targetComp: "); pw.println(r.targetComp.toShortString());
+                }
+                Bundle bundle = r.intent.getExtras();
+                if (bundle != null) {
+                    pw.print("    extras: "); pw.println(bundle.toString());
+                }
+            }
+        } while (ringIndex != lastIndex);
+
+        if (dumpPackage == null) {
+            lastIndex = ringIndex = mSummaryHistoryNext;
+            if (dumpAll) {
+                printed = false;
+                i = -1;
+            } else {
+                // roll over the 'i' full dumps that have already been issued
+                for (int j = i;
+                        j > 0 && ringIndex != lastIndex;) {
+                    ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+                    BroadcastRecord r = mBroadcastHistory[ringIndex];
+                    if (r == null) {
+                        continue;
+                    }
+                    j--;
+                }
+            }
+            // done skipping; dump the remainder of the ring. 'i' is still the ordinal within
+            // the overall broadcast history.
+            do {
+                ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
+                Intent intent = mBroadcastSummaryHistory[ringIndex];
+                if (intent == null) {
+                    continue;
+                }
+                if (!printed) {
+                    if (needSep) {
+                        pw.println();
+                    }
+                    needSep = true;
+                    pw.println("  Historical broadcasts summary [" + queueName + "]:");
+                    printed = true;
+                }
+                if (!dumpAll && i >= 50) {
+                    pw.println("  ...");
+                    break;
+                }
+                i++;
+                pw.print("  #"); pw.print(i); pw.print(": ");
+                pw.println(intent.toShortString(false, true, true, false));
+                pw.print("    ");
+                TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
+                        - mSummaryHistoryEnqueueTime[ringIndex], pw);
+                pw.print(" dispatch ");
+                TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
+                        - mSummaryHistoryDispatchTime[ringIndex], pw);
+                pw.println(" finish");
+                pw.print("    enq=");
+                pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
+                pw.print(" disp=");
+                pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
+                pw.print(" fin=");
+                pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
+                Bundle bundle = intent.getExtras();
+                if (bundle != null) {
+                    pw.print("    extras: "); pw.println(bundle.toString());
+                }
+            } while (ringIndex != lastIndex);
+        }
+        return needSep;
+    }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 9be22c0..6814509 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -16,16 +16,19 @@
 
 package com.android.server.am;
 
-import android.content.BroadcastReceiver;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.IBinder;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -34,22 +37,25 @@
 public abstract class BroadcastQueue {
     public static final String TAG = "BroadcastQueue";
 
-    final ActivityManagerService mService;
-    final Handler mHandler;
-    final BroadcastConstants mConstants;
-    final BroadcastSkipPolicy mSkipPolicy;
-    final String mQueueName;
+    final @NonNull ActivityManagerService mService;
+    final @NonNull Handler mHandler;
+    final @NonNull BroadcastConstants mConstants;
+    final @NonNull BroadcastSkipPolicy mSkipPolicy;
+    final @NonNull BroadcastHistory mHistory;
+    final @NonNull String mQueueName;
 
-    BroadcastQueue(ActivityManagerService service, Handler handler,
-            String name, BroadcastConstants constants) {
-        mService = service;
-        mHandler = handler;
-        mQueueName = name;
-        mConstants = constants;
-        mSkipPolicy = new BroadcastSkipPolicy(service);
+    BroadcastQueue(@NonNull ActivityManagerService service, @NonNull Handler handler,
+            @NonNull String name, @NonNull BroadcastConstants constants,
+            @NonNull BroadcastSkipPolicy skipPolicy, @NonNull BroadcastHistory history) {
+        mService = Objects.requireNonNull(service);
+        mHandler = Objects.requireNonNull(handler);
+        mQueueName = Objects.requireNonNull(name);
+        mConstants = Objects.requireNonNull(constants);
+        mSkipPolicy = Objects.requireNonNull(skipPolicy);
+        mHistory = Objects.requireNonNull(history);
     }
 
-    void start(ContentResolver resolver) {
+    void start(@NonNull ContentResolver resolver) {
         mConstants.startObserving(mHandler, resolver);
     }
 
@@ -60,9 +66,15 @@
 
     public abstract boolean isDelayBehindServices();
 
-    public abstract BroadcastRecord getPendingBroadcastLocked();
-
-    public abstract BroadcastRecord getActiveBroadcastLocked();
+    /**
+     * Return the preferred scheduling group for the given process, typically
+     * influenced by a broadcast being actively dispatched.
+     *
+     * @return scheduling group such as {@link ProcessList#SCHED_GROUP_DEFAULT},
+     *         otherwise {@link ProcessList#SCHED_GROUP_UNDEFINED} if this queue
+     *         has no opinion.
+     */
+    public abstract int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app);
 
     /**
      * Enqueue the given broadcast to be eventually dispatched.
@@ -73,78 +85,105 @@
      * When {@link Intent#FLAG_RECEIVER_REPLACE_PENDING} is set, this method
      * internally handles replacement of any matching broadcasts.
      */
-    public abstract void enqueueBroadcastLocked(BroadcastRecord r);
-
-    public abstract BroadcastRecord getMatchingOrderedReceiver(IBinder receiver);
+    @GuardedBy("mService")
+    public abstract void enqueueBroadcastLocked(@NonNull BroadcastRecord r);
 
     /**
-     * Signal delivered back from a {@link BroadcastReceiver} to indicate that
-     * it's finished processing the current broadcast being dispatched to it.
+     * Signal delivered back from the given process to indicate that it's
+     * finished processing the current broadcast being dispatched to it.
      * <p>
      * If this signal isn't delivered back in a timely fashion, we assume the
      * receiver has somehow wedged and we trigger an ANR.
      */
-    public abstract boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
-            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices);
+    @GuardedBy("mService")
+    public abstract boolean finishReceiverLocked(@NonNull ProcessRecord app, int resultCode,
+            @Nullable String resultData, @Nullable Bundle resultExtras, boolean resultAbort,
+            boolean waitForServices);
 
+    @GuardedBy("mService")
     public abstract void backgroundServicesFinishedLocked(int userId);
 
     /**
      * Signal from OS internals that the given process has just been actively
      * attached, and is ready to begin receiving broadcasts.
      */
-    public abstract boolean onApplicationAttachedLocked(ProcessRecord app);
+    @GuardedBy("mService")
+    public abstract boolean onApplicationAttachedLocked(@NonNull ProcessRecord app);
 
     /**
      * Signal from OS internals that the given process has timed out during
      * an attempted start and attachment.
      */
-    public abstract boolean onApplicationTimeoutLocked(ProcessRecord app);
+    @GuardedBy("mService")
+    public abstract boolean onApplicationTimeoutLocked(@NonNull ProcessRecord app);
 
     /**
      * Signal from OS internals that the given process, which had already been
      * previously attached, has now encountered a problem such as crashing or
      * not responding.
      */
-    public abstract boolean onApplicationProblemLocked(ProcessRecord app);
+    @GuardedBy("mService")
+    public abstract boolean onApplicationProblemLocked(@NonNull ProcessRecord app);
 
     /**
      * Signal from OS internals that the given process has been killed, and is
      * no longer actively running.
      */
-    public abstract boolean onApplicationCleanupLocked(ProcessRecord app);
+    @GuardedBy("mService")
+    public abstract boolean onApplicationCleanupLocked(@NonNull ProcessRecord app);
 
     /**
      * Signal from OS internals that the given package (or some subset of that
      * package) has been disabled or uninstalled, and that any pending
      * broadcasts should be cleaned up.
      */
-    public abstract boolean cleanupDisabledPackageReceiversLocked(
-            String packageName, Set<String> filterByClasses, int userId, boolean doit);
+    @GuardedBy("mService")
+    public abstract boolean cleanupDisabledPackageReceiversLocked(@Nullable String packageName,
+            @Nullable Set<String> filterByClasses, int userId, boolean doit);
 
     /**
      * Quickly determine if this queue has broadcasts that are still waiting to
      * be delivered at some point in the future.
      *
-     * @see #flush()
+     * @see #waitForIdle
+     * @see #waitForBarrier
      */
-    public abstract boolean isIdle();
+    @GuardedBy("mService")
+    public abstract boolean isIdleLocked();
+
+    /**
+     * Wait until this queue becomes completely idle.
+     * <p>
+     * Any broadcasts waiting to be delivered at some point in the future will
+     * be dispatched as quickly as possible.
+     * <p>
+     * Callers are cautioned that the queue may take a long time to go idle,
+     * since running apps can continue sending new broadcasts in perpetuity;
+     * consider using {@link #waitForBarrier} instead.
+     */
+    public abstract void waitForIdle(@Nullable PrintWriter pw);
+
+    /**
+     * Wait until any currently waiting broadcasts have been dispatched.
+     * <p>
+     * Any broadcasts waiting to be delivered at some point in the future will
+     * be dispatched as quickly as possible.
+     * <p>
+     * Callers are advised that this method will <em>not</em> wait for any
+     * future broadcasts that are newly enqueued after being invoked.
+     */
+    public abstract void waitForBarrier(@Nullable PrintWriter pw);
 
     /**
      * Brief summary of internal state, useful for debugging purposes.
      */
-    public abstract String describeState();
+    @GuardedBy("mService")
+    public abstract @NonNull String describeStateLocked();
 
-    /**
-     * Flush any broadcasts still waiting to be delivered, causing them to be
-     * delivered as soon as possible.
-     *
-     * @see #isIdle()
-     */
-    public abstract void flush();
+    public abstract void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId);
 
-    public abstract void dumpDebug(ProtoOutputStream proto, long fieldId);
-
-    public abstract boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
-            int opti, boolean dumpAll, String dumpPackage, boolean needSep);
+    @GuardedBy("mService")
+    public abstract boolean dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+            @NonNull String[] args, int opti, boolean dumpAll, @Nullable String dumpPackage,
+            boolean needSep);
 }
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index 2b3b211..56112cf 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -42,7 +42,6 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
-import android.app.AppGlobals;
 import android.app.BroadcastOptions;
 import android.app.IApplicationThread;
 import android.app.RemoteServiceException.CannotDeliverBroadcastException;
@@ -74,7 +73,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseIntArray;
-import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.os.TimeoutRecord;
@@ -86,8 +84,8 @@
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.Set;
+import java.util.function.BooleanSupplier;
 
 /**
  * BROADCASTS
@@ -100,16 +98,14 @@
     private static final String TAG_MU = TAG + POSTFIX_MU;
     private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
 
-    static final int MAX_BROADCAST_HISTORY = ActivityManager.isLowRamDeviceStatic() ? 10 : 50;
-    static final int MAX_BROADCAST_SUMMARY_HISTORY
-            = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
-
     /**
      * If true, we can delay broadcasts while waiting services to finish in the previous
      * receiver's process.
      */
     final boolean mDelayBehindServices;
 
+    final int mSchedGroup;
+
     /**
      * Lists of all active broadcasts that are to be executed immediately
      * (without waiting for another broadcast to finish).  Currently this only
@@ -134,29 +130,6 @@
     private int mNextToken = 0;
 
     /**
-     * Historical data of past broadcasts, for debugging.  This is a ring buffer
-     * whose last element is at mHistoryNext.
-     */
-    final BroadcastRecord[] mBroadcastHistory = new BroadcastRecord[MAX_BROADCAST_HISTORY];
-    int mHistoryNext = 0;
-
-    /**
-     * Summary of historical data of past broadcasts, for debugging.  This is a
-     * ring buffer whose last element is at mSummaryHistoryNext.
-     */
-    final Intent[] mBroadcastSummaryHistory = new Intent[MAX_BROADCAST_SUMMARY_HISTORY];
-    int mSummaryHistoryNext = 0;
-
-    /**
-     * Various milestone timestamps of entries in the mBroadcastSummaryHistory ring
-     * buffer, also tracked via the mSummaryHistoryNext index.  These are all in wall
-     * clock time, not elapsed.
-     */
-    final long[] mSummaryHistoryEnqueueTime = new  long[MAX_BROADCAST_SUMMARY_HISTORY];
-    final long[] mSummaryHistoryDispatchTime = new  long[MAX_BROADCAST_SUMMARY_HISTORY];
-    final long[] mSummaryHistoryFinishTime = new  long[MAX_BROADCAST_SUMMARY_HISTORY];
-
-    /**
      * Set when we current have a BROADCAST_INTENT_MSG in flight.
      */
     boolean mBroadcastsScheduled = false;
@@ -212,10 +185,19 @@
     }
 
     BroadcastQueueImpl(ActivityManagerService service, Handler handler,
-            String name, BroadcastConstants constants, boolean allowDelayBehindServices) {
-        super(service, handler, name, constants);
+            String name, BroadcastConstants constants, boolean allowDelayBehindServices,
+            int schedGroup) {
+        this(service, handler, name, constants, new BroadcastSkipPolicy(service),
+                new BroadcastHistory(), allowDelayBehindServices, schedGroup);
+    }
+
+    BroadcastQueueImpl(ActivityManagerService service, Handler handler,
+            String name, BroadcastConstants constants, BroadcastSkipPolicy skipPolicy,
+            BroadcastHistory history, boolean allowDelayBehindServices, int schedGroup) {
+        super(service, handler, name, constants, skipPolicy, history);
         mHandler = new BroadcastHandler(handler.getLooper());
         mDelayBehindServices = allowDelayBehindServices;
+        mSchedGroup = schedGroup;
         mDispatcher = new BroadcastDispatcher(this, mConstants, mHandler, mService);
     }
 
@@ -236,6 +218,18 @@
         return mDispatcher.getActiveBroadcastLocked();
     }
 
+    public int getPreferredSchedulingGroupLocked(ProcessRecord app) {
+        final BroadcastRecord active = getActiveBroadcastLocked();
+        if (active != null && active.curApp == app) {
+            return mSchedGroup;
+        }
+        final BroadcastRecord pending = getPendingBroadcastLocked();
+        if (pending != null && pending.curApp == app) {
+            return mSchedGroup;
+        }
+        return ProcessList.SCHED_GROUP_UNDEFINED;
+    }
+
     public void enqueueBroadcastLocked(BroadcastRecord r) {
         final boolean replacePending = (r.intent.getFlags()
                 & Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
@@ -363,7 +357,6 @@
             return;
         }
 
-        r.receiver = thread.asBinder();
         r.curApp = app;
         final ProcessReceiverRecord prr = app.mReceivers;
         prr.addCurReceiver(r);
@@ -401,7 +394,6 @@
             if (!started) {
                 if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                         "Process cur broadcast " + r + ": NOT STARTED!");
-                r.receiver = null;
                 r.curApp = null;
                 prr.removeCurReceiver(r);
             }
@@ -518,12 +510,19 @@
         mBroadcastsScheduled = true;
     }
 
-    public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+    public BroadcastRecord getMatchingOrderedReceiver(ProcessRecord app) {
         BroadcastRecord br = mDispatcher.getActiveBroadcastLocked();
-        if (br != null && br.receiver == receiver) {
-            return br;
+        if (br == null) {
+            Slog.w(TAG_BROADCAST, "getMatchingOrderedReceiver [" + mQueueName
+                    + "] no active broadcast");
+            return null;
         }
-        return null;
+        if (br.curApp != app) {
+            Slog.w(TAG_BROADCAST, "getMatchingOrderedReceiver [" + mQueueName
+                    + "] active broadcast " + br.curApp + " doesn't match " + app);
+            return null;
+        }
+        return br;
     }
 
     // > 0 only, no worry about "eventual" recycling
@@ -551,6 +550,17 @@
         }, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT));
     }
 
+    public boolean finishReceiverLocked(ProcessRecord app, int resultCode,
+            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
+        final BroadcastRecord r = getMatchingOrderedReceiver(app);
+        if (r != null) {
+            return finishReceiverLocked(r, resultCode,
+                    resultData, resultExtras, resultAbort, waitForServices);
+        } else {
+            return false;
+        }
+    }
+
     public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
             String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
         final int state = r.state;
@@ -623,7 +633,6 @@
             }
         }
 
-        r.receiver = null;
         r.intent.setComponent(null);
         if (r.curApp != null && r.curApp.mReceivers.hasCurReceiver(r)) {
             r.curApp.mReceivers.removeCurReceiver(r);
@@ -650,7 +659,7 @@
         // If we want to wait behind services *AND* we're finishing the head/
         // active broadcast on its queue
         if (waitForServices && r.curComponent != null && r.queue.isDelayBehindServices()
-                && r.queue.getActiveBroadcastLocked() == r) {
+                && ((BroadcastQueueImpl) r.queue).getActiveBroadcastLocked() == r) {
             ActivityInfo nextReceiver;
             if (r.nextReceiver < r.receivers.size()) {
                 Object obj = r.receivers.get(r.nextReceiver);
@@ -781,7 +790,6 @@
         // don't want to touch the fields that keep track of the current
         // state of ordered broadcasts.
         if (ordered) {
-            r.receiver = filter.receiverList.receiver.asBinder();
             r.curFilter = filter;
             filter.receiverList.curBroadcast = r;
             r.state = BroadcastRecord.CALL_IN_RECEIVE;
@@ -845,7 +853,6 @@
             }
             // And BroadcastRecord state related to ordered delivery, if appropriate
             if (ordered) {
-                r.receiver = null;
                 r.curFilter = null;
                 filter.receiverList.curBroadcast = null;
             }
@@ -1265,12 +1272,13 @@
                     + filter + ": " + r);
             r.mIsReceiverAppRunning = true;
             deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
-            if (r.receiver == null || !r.ordered) {
+            if ((r.curReceiver == null && r.curFilter == null) || !r.ordered) {
                 // The receiver has already finished, so schedule to
                 // process the next one.
                 if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
-                        + mQueueName + "]: ordered="
-                        + r.ordered + " receiver=" + r.receiver);
+                        + mQueueName + "]: ordered=" + r.ordered
+                        + " curFilter=" + r.curFilter
+                        + " curReceiver=" + r.curReceiver);
                 r.state = BroadcastRecord.IDLE;
                 scheduleBroadcastsLocked();
             } else {
@@ -1322,7 +1330,6 @@
                     "Skipping delivery of ordered [" + mQueueName + "] "
                     + r + " for reason described above");
             r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
-            r.receiver = null;
             r.curFilter = null;
             r.state = BroadcastRecord.IDLE;
             r.manifestSkipCount++;
@@ -1354,9 +1361,8 @@
 
         // Broadcast is being executed, its package can't be stopped.
         try {
-            AppGlobals.getPackageManager().setPackageStoppedState(
+            mService.mPackageManagerInt.setPackageStoppedState(
                     r.curComponent.getPackageName(), false, r.userId);
-        } catch (RemoteException e) {
         } catch (IllegalArgumentException e) {
             Slog.w(TAG, "Failed trying to unstop package "
                     + r.curComponent.getPackageName() + ": " + e);
@@ -1613,8 +1619,8 @@
         final boolean debugging = (r.curApp != null && r.curApp.isDebugging());
 
         long timeoutDurationMs = now - r.receiverTime;
-        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
-                + ", started " + timeoutDurationMs + "ms ago");
+        Slog.w(TAG, "Timeout of broadcast " + r + " - curFilter=" + r.curFilter + " curReceiver="
+                + r.curReceiver + ", started " + timeoutDurationMs + "ms ago");
         r.receiverTime = now;
         if (!debugging) {
             r.anrCount++;
@@ -1666,13 +1672,6 @@
         }
     }
 
-    private final int ringAdvance(int x, final int increment, final int ringSize) {
-        x += increment;
-        if (x < 0) return (ringSize - 1);
-        else if (x >= ringSize) return 0;
-        else return x;
-    }
-
     private final void addBroadcastToHistoryLocked(BroadcastRecord original) {
         if (original.callingUid < 0) {
             // This was from a registerReceiver() call; ignore it.
@@ -1693,18 +1692,7 @@
                     original.callingUid, 0, callerPackage).sendToTarget();
         }
 
-        // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
-        // So don't change the incoming record directly.
-        final BroadcastRecord historyRecord = original.maybeStripForHistory();
-
-        mBroadcastHistory[mHistoryNext] = historyRecord;
-        mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
-
-        mBroadcastSummaryHistory[mSummaryHistoryNext] = historyRecord.intent;
-        mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = historyRecord.enqueueClockTime;
-        mSummaryHistoryDispatchTime[mSummaryHistoryNext] = historyRecord.dispatchClockTime;
-        mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
-        mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
+        mHistory.addBroadcastToHistoryLocked(original);
     }
 
     public boolean cleanupDisabledPackageReceiversLocked(
@@ -1758,13 +1746,72 @@
                 record.intent == null ? "" : record.intent.getAction());
     }
 
-    public boolean isIdle() {
+    public boolean isIdleLocked() {
         return mParallelBroadcasts.isEmpty() && mDispatcher.isIdle()
                 && (mPendingBroadcast == null);
     }
 
-    public void flush() {
-        cancelDeferrals();
+    public boolean isBeyondBarrierLocked(long barrierTime) {
+        // If nothing active, we're beyond barrier
+        if (isIdleLocked()) return true;
+
+        // Check if active broadcast is beyond barrier
+        final BroadcastRecord active = getActiveBroadcastLocked();
+        if (active != null && active.enqueueTime > barrierTime) {
+            return true;
+        }
+
+        // Check if pending broadcast is beyond barrier
+        final BroadcastRecord pending = getPendingBroadcastLocked();
+        if (pending != null && pending.enqueueTime > barrierTime) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public void waitForIdle(PrintWriter pw) {
+        waitFor(() -> isIdleLocked(), pw, "idle");
+    }
+
+    public void waitForBarrier(PrintWriter pw) {
+        final long barrierTime = SystemClock.uptimeMillis();
+        waitFor(() -> isBeyondBarrierLocked(barrierTime), pw, "barrier");
+    }
+
+    private void waitFor(BooleanSupplier condition, PrintWriter pw, String conditionName) {
+        long lastPrint = 0;
+        while (true) {
+            synchronized (mService) {
+                if (condition.getAsBoolean()) {
+                    final String msg = "Queue [" + mQueueName + "] reached " + conditionName
+                            + " condition";
+                    Slog.v(TAG, msg);
+                    if (pw != null) {
+                        pw.println(msg);
+                        pw.flush();
+                    }
+                    return;
+                }
+            }
+
+            // Print at most every second
+            final long now = SystemClock.uptimeMillis();
+            if (now >= lastPrint + 1000) {
+                lastPrint = now;
+                final String msg = "Queue [" + mQueueName + "] waiting for " + conditionName
+                        + " condition; state is " + describeStateLocked();
+                Slog.v(TAG, msg);
+                if (pw != null) {
+                    pw.println(msg);
+                    pw.flush();
+                }
+            }
+
+            // Push through any deferrals to try meeting our condition
+            cancelDeferrals();
+            SystemClock.sleep(100);
+        }
     }
 
     // Used by wait-for-broadcast-idle : fast-forward all current deferrals to
@@ -1776,11 +1823,9 @@
         }
     }
 
-    public String describeState() {
-        synchronized (mService) {
-            return mParallelBroadcasts.size() + " parallel; "
-                    + mDispatcher.describeStateLocked();
-        }
+    public String describeStateLocked() {
+        return mParallelBroadcasts.size() + " parallel; "
+                + mDispatcher.describeStateLocked();
     }
 
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
@@ -1795,37 +1840,7 @@
         if (mPendingBroadcast != null) {
             mPendingBroadcast.dumpDebug(proto, BroadcastQueueProto.PENDING_BROADCAST);
         }
-
-        int lastIndex = mHistoryNext;
-        int ringIndex = lastIndex;
-        do {
-            // increasing index = more recent entry, and we want to print the most
-            // recent first and work backwards, so we roll through the ring backwards.
-            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
-            BroadcastRecord r = mBroadcastHistory[ringIndex];
-            if (r != null) {
-                r.dumpDebug(proto, BroadcastQueueProto.HISTORICAL_BROADCASTS);
-            }
-        } while (ringIndex != lastIndex);
-
-        lastIndex = ringIndex = mSummaryHistoryNext;
-        do {
-            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
-            Intent intent = mBroadcastSummaryHistory[ringIndex];
-            if (intent == null) {
-                continue;
-            }
-            long summaryToken = proto.start(BroadcastQueueProto.HISTORICAL_BROADCASTS_SUMMARY);
-            intent.dumpDebug(proto, BroadcastQueueProto.BroadcastSummary.INTENT,
-                    false, true, true, false);
-            proto.write(BroadcastQueueProto.BroadcastSummary.ENQUEUE_CLOCK_TIME_MS,
-                    mSummaryHistoryEnqueueTime[ringIndex]);
-            proto.write(BroadcastQueueProto.BroadcastSummary.DISPATCH_CLOCK_TIME_MS,
-                    mSummaryHistoryDispatchTime[ringIndex]);
-            proto.write(BroadcastQueueProto.BroadcastSummary.FINISH_CLOCK_TIME_MS,
-                    mSummaryHistoryFinishTime[ringIndex]);
-            proto.end(summaryToken);
-        } while (ringIndex != lastIndex);
+        mHistory.dumpDebug(proto);
         proto.end(token);
     }
 
@@ -1866,114 +1881,8 @@
                 needSep = true;
             }
         }
-
         mConstants.dump(pw);
-
-        int i;
-        boolean printed = false;
-
-        i = -1;
-        int lastIndex = mHistoryNext;
-        int ringIndex = lastIndex;
-        do {
-            // increasing index = more recent entry, and we want to print the most
-            // recent first and work backwards, so we roll through the ring backwards.
-            ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_HISTORY);
-            BroadcastRecord r = mBroadcastHistory[ringIndex];
-            if (r == null) {
-                continue;
-            }
-
-            i++; // genuine record of some sort even if we're filtering it out
-            if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
-                continue;
-            }
-            if (!printed) {
-                if (needSep) {
-                    pw.println();
-                }
-                needSep = true;
-                pw.println("  Historical broadcasts [" + mQueueName + "]:");
-                printed = true;
-            }
-            if (dumpAll) {
-                pw.print("  Historical Broadcast " + mQueueName + " #");
-                        pw.print(i); pw.println(":");
-                r.dump(pw, "    ", sdf);
-            } else {
-                pw.print("  #"); pw.print(i); pw.print(": "); pw.println(r);
-                pw.print("    ");
-                pw.println(r.intent.toShortString(false, true, true, false));
-                if (r.targetComp != null && r.targetComp != r.intent.getComponent()) {
-                    pw.print("    targetComp: "); pw.println(r.targetComp.toShortString());
-                }
-                Bundle bundle = r.intent.getExtras();
-                if (bundle != null) {
-                    pw.print("    extras: "); pw.println(bundle.toString());
-                }
-            }
-        } while (ringIndex != lastIndex);
-
-        if (dumpPackage == null) {
-            lastIndex = ringIndex = mSummaryHistoryNext;
-            if (dumpAll) {
-                printed = false;
-                i = -1;
-            } else {
-                // roll over the 'i' full dumps that have already been issued
-                for (int j = i;
-                        j > 0 && ringIndex != lastIndex;) {
-                    ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
-                    BroadcastRecord r = mBroadcastHistory[ringIndex];
-                    if (r == null) {
-                        continue;
-                    }
-                    j--;
-                }
-            }
-            // done skipping; dump the remainder of the ring. 'i' is still the ordinal within
-            // the overall broadcast history.
-            do {
-                ringIndex = ringAdvance(ringIndex, -1, MAX_BROADCAST_SUMMARY_HISTORY);
-                Intent intent = mBroadcastSummaryHistory[ringIndex];
-                if (intent == null) {
-                    continue;
-                }
-                if (!printed) {
-                    if (needSep) {
-                        pw.println();
-                    }
-                    needSep = true;
-                    pw.println("  Historical broadcasts summary [" + mQueueName + "]:");
-                    printed = true;
-                }
-                if (!dumpAll && i >= 50) {
-                    pw.println("  ...");
-                    break;
-                }
-                i++;
-                pw.print("  #"); pw.print(i); pw.print(": ");
-                pw.println(intent.toShortString(false, true, true, false));
-                pw.print("    ");
-                TimeUtils.formatDuration(mSummaryHistoryDispatchTime[ringIndex]
-                        - mSummaryHistoryEnqueueTime[ringIndex], pw);
-                pw.print(" dispatch ");
-                TimeUtils.formatDuration(mSummaryHistoryFinishTime[ringIndex]
-                        - mSummaryHistoryDispatchTime[ringIndex], pw);
-                pw.println(" finish");
-                pw.print("    enq=");
-                pw.print(sdf.format(new Date(mSummaryHistoryEnqueueTime[ringIndex])));
-                pw.print(" disp=");
-                pw.print(sdf.format(new Date(mSummaryHistoryDispatchTime[ringIndex])));
-                pw.print(" fin=");
-                pw.println(sdf.format(new Date(mSummaryHistoryFinishTime[ringIndex])));
-                Bundle bundle = intent.getExtras();
-                if (bundle != null) {
-                    pw.print("    extras: "); pw.println(bundle.toString());
-                }
-            } while (ringIndex != lastIndex);
-        }
-
+        needSep = mHistory.dumpLocked(pw, dumpPackage, mQueueName, sdf, dumpAll, needSep);
         return needSep;
     }
 }
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 18fbfde..817831c 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -103,7 +103,6 @@
     Bundle resultExtras;    // current result extra data values.
     boolean resultAbort;    // current result abortBroadcast value.
     int nextReceiver;       // next receiver to be executed.
-    IBinder receiver;       // who is currently running, null if none.
     int state;
     int anrCount;           // has this broadcast record hit any ANRs?
     int manifestCount;      // number of manifest receivers dispatched.
@@ -133,15 +132,10 @@
     static final int DELIVERY_SKIPPED = 2;
     static final int DELIVERY_TIMEOUT = 3;
 
-    // The following are set when we are calling a receiver (one that
-    // was found in our list of registered receivers).
-    BroadcastFilter curFilter;
-
-    // The following are set only when we are launching a receiver (one
-    // that was found by querying the package manager).
     ProcessRecord curApp;       // hosting application of current receiver.
     ComponentName curComponent; // the receiver class that is currently running.
-    ActivityInfo curReceiver;   // info about the receiver that is currently running.
+    ActivityInfo curReceiver;   // the manifest receiver that is currently running.
+    BroadcastFilter curFilter;  // the registered receiver currently running.
     Bundle curFilteredExtras;   // the bundle that has been filtered by the package visibility rules
 
     boolean mIsReceiverAppRunning; // Was the receiver's app already running.
@@ -217,9 +211,8 @@
                     pw.print(" sticky="); pw.print(sticky);
                     pw.print(" initialSticky="); pw.println(initialSticky);
         }
-        if (nextReceiver != 0 || receiver != null) {
+        if (nextReceiver != 0) {
             pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver);
-                    pw.print(" receiver="); pw.println(receiver);
         }
         if (curFilter != null) {
             pw.print(prefix); pw.print("curFilter="); pw.println(curFilter);
@@ -368,7 +361,6 @@
         resultExtras = from.resultExtras;
         resultAbort = from.resultAbort;
         nextReceiver = from.nextReceiver;
-        receiver = from.receiver;
         state = from.state;
         anrCount = from.anrCount;
         manifestCount = from.manifestCount;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 653b602..4574302 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -40,18 +40,19 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.ProcLocksReader;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.ServiceThread;
+
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.EnumMap;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedList;
@@ -109,6 +110,7 @@
     private static final int COMPACT_ACTION_ANON_FLAG = 2;
 
     private static final String ATRACE_COMPACTION_TRACK = "Compaction";
+    private static final String ATRACE_FREEZER_TRACK = "Freezer";
 
     // Defaults for phenotype flags.
     @VisibleForTesting static final Boolean DEFAULT_USE_COMPACTION = false;
@@ -1309,6 +1311,7 @@
         }
 
         try {
+            traceAppFreeze(app.processName, pid, false);
             Process.setProcessFrozen(pid, app.uid, false);
 
             opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis());
@@ -1351,10 +1354,27 @@
                 return;
             }
             Slog.d(TAG_AM, "quick sync unfreeze " + pid);
-            unfreezeAppLSP(app, reason);
+            try {
+                freezeBinder(pid, false);
+            } catch (RuntimeException e) {
+                Slog.e(TAG_AM, "Unable to quick unfreeze binder for " + pid);
+                return;
+            }
+
+            try {
+                traceAppFreeze(app.processName, pid, false);
+                Process.setProcessFrozen(pid, app.uid, false);
+            } catch (Exception e) {
+                Slog.e(TAG_AM, "Unable to quick unfreeze " + pid);
+            }
         }
     }
 
+    private static void traceAppFreeze(String processName, int pid, boolean freeze) {
+        Trace.instantForTrack(Trace.TRACE_TAG_ACTIVITY_MANAGER, ATRACE_FREEZER_TRACK,
+                (freeze ? "Freeze " : "Unfreeze ") + processName + ":" + pid);
+    }
+
     /**
      * To be called when the given app is killed.
      */
@@ -1948,6 +1968,7 @@
                 long unfreezeTime = opt.getFreezeUnfreezeTime();
 
                 try {
+                    traceAppFreeze(proc.processName, pid, true);
                     Process.setProcessFrozen(pid, proc.uid, true);
 
                     opt.setFreezeUnfreezeTime(SystemClock.uptimeMillis());
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 9abd01a..86c9770 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -29,7 +29,6 @@
 import static com.android.server.am.ActivityManagerService.TAG_MU;
 import static com.android.server.am.ProcessProfileRecord.HOSTING_COMPONENT_TYPE_PROVIDER;
 
-import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -49,6 +48,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.pm.UserInfo;
@@ -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;
@@ -464,10 +464,9 @@
                         try {
                             checkTime(startTime,
                                     "getContentProviderImpl: before set stopped state");
-                            AppGlobals.getPackageManager().setPackageStoppedState(
+                            mService.mPackageManagerInt.setPackageStoppedState(
                                     cpr.appInfo.packageName, false, userId);
                             checkTime(startTime, "getContentProviderImpl: after set stopped state");
-                        } catch (RemoteException e) {
                         } catch (IllegalArgumentException e) {
                             Slog.w(TAG, "Failed trying to unstop package "
                                     + cpr.appInfo.packageName + ": " + e);
@@ -961,22 +960,20 @@
     String getProviderMimeType(Uri uri, int userId) {
         mService.enforceNotIsolatedCaller("getProviderMimeType");
         final String name = uri.getAuthority();
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
-        final long ident = canClearIdentity(callingPid, callingUid, safeUserId)
-                ? Binder.clearCallingIdentity() : 0;
-        final ContentProviderHolder holder;
+        int callingUid = Binder.getCallingUid();
+        int callingPid = Binder.getCallingPid();
+        long ident = 0;
+        boolean clearedIdentity = false;
+        userId = mService.mUserController.unsafeConvertIncomingUser(userId);
+        if (canClearIdentity(callingPid, callingUid, userId)) {
+            clearedIdentity = true;
+            ident = Binder.clearCallingIdentity();
+        }
+        ContentProviderHolder holder = null;
         try {
             holder = getContentProviderExternalUnchecked(name, null, callingUid,
-                    "*getmimetype*", safeUserId);
-        } finally {
-            if (ident != 0) {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-        try {
-            if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) {
+                    "*getmimetype*", userId);
+            if (holder != null) {
                 final IBinder providerConnection = holder.connection;
                 final ComponentName providerName = holder.info.getComponentName();
                 // Note: creating a new Runnable instead of using a lambda here since lambdas in
@@ -1005,13 +1002,15 @@
             return null;
         } finally {
             // We need to clear the identity to call removeContentProviderExternalUnchecked
-            final long token = Binder.clearCallingIdentity();
+            if (!clearedIdentity) {
+                ident = Binder.clearCallingIdentity();
+            }
             try {
                 if (holder != null) {
-                    removeContentProviderExternalUnchecked(name, null /* token */, safeUserId);
+                    removeContentProviderExternalUnchecked(name, null, userId);
                 }
             } finally {
-                Binder.restoreCallingIdentity(token);
+                Binder.restoreCallingIdentity(ident);
             }
         }
 
@@ -1030,20 +1029,12 @@
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
         final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
-        final long ident = canClearIdentity(callingPid, callingUid, safeUserId)
+        final long ident = canClearIdentity(callingPid, callingUid, userId)
                 ? Binder.clearCallingIdentity() : 0;
-        final ContentProviderHolder holder;
         try {
-            holder = getContentProviderExternalUnchecked(name, null /* token */,
+            final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null,
                     callingUid, "*getmimetype*", safeUserId);
-        } finally {
-            if (ident != 0) {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        try {
-            if (isHolderVisibleToCaller(holder, callingUid, safeUserId)) {
+            if (holder != null) {
                 holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
                     final long identity = Binder.clearCallingIdentity();
                     try {
@@ -1059,6 +1050,8 @@
         } catch (RemoteException e) {
             Log.w(TAG, "Content provider dead retrieving " + uri, e);
             resultCallback.sendResult(Bundle.EMPTY);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -1074,16 +1067,6 @@
                         callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
     }
 
-    private boolean isHolderVisibleToCaller(@Nullable ContentProviderHolder holder, int callingUid,
-            @UserIdInt int userId) {
-        if (holder == null || holder.info == null) {
-            return false;
-        }
-
-        return !mService.getPackageManagerInternal()
-                .filterAppAccess(holder.info.packageName, callingUid, userId);
-    }
-
     /**
      * Check if the calling UID has a possible chance at accessing the provider
      * at the given authority and user.
@@ -1152,7 +1135,9 @@
                     "*checkContentProviderUriPermission*", userId);
             if (holder != null) {
 
-                final AndroidPackage androidPackage = mService.getPackageManagerInternal()
+                final PackageManagerInternal packageManagerInt = LocalServices.getService(
+                        PackageManagerInternal.class);
+                final AndroidPackage androidPackage = packageManagerInt
                         .getPackage(Binder.getCallingUid());
                 if (androidPackage == null) {
                     return PackageManager.PERMISSION_DENIED;
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index baf062d..e5975c3 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -19,11 +19,13 @@
 import android.os.SystemClock;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
+import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
 
 /** Rate limiter for adding errors into dropbox. */
 public class DropboxRateLimiter {
+    private static final String TAG = "DropboxRateLimiter";
     // After RATE_LIMIT_ALLOWED_ENTRIES have been collected (for a single breakdown of
     // process/eventType) further entries will be rejected until RATE_LIMIT_BUFFER_DURATION has
     // elapsed, after which the current count for this breakdown will be reset.
@@ -105,6 +107,15 @@
         mLastMapCleanUp = now;
     }
 
+    /** Resets the rate limiter memory. */
+    public void reset() {
+        synchronized (mErrorClusterRecords) {
+            mErrorClusterRecords.clear();
+        }
+        mLastMapCleanUp = 0L;
+        Slog.i(TAG, "Rate limiter reset.");
+    }
+
     String errorKey(String eventType, String processName) {
         return eventType + processName;
     }
diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java
index 2498f76..30811a1 100644
--- a/services/core/java/com/android/server/am/HostingRecord.java
+++ b/services/core/java/com/android/server/am/HostingRecord.java
@@ -30,9 +30,10 @@
 import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_SERVICE;
 import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_SYSTEM;
 import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_TOP_ACTIVITY;
-import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE;
-import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE_OVER_QUOTA;
 import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_ALARM;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_JOB;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA;
 import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_UNKNOWN;
 import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__TYPE__UNKNOWN;
 
@@ -97,6 +98,7 @@
     public static final String TRIGGER_TYPE_ALARM = "alarm";
     public static final String TRIGGER_TYPE_PUSH_MESSAGE = "push_message";
     public static final String TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA = "push_message_over_quota";
+    public static final String TRIGGER_TYPE_JOB = "job";
 
     @NonNull private final String mHostingType;
     private final String mHostingName;
@@ -126,10 +128,11 @@
     }
 
     public HostingRecord(@NonNull String hostingType, ComponentName hostingName,
-            String definingPackageName, int definingUid, String definingProcessName) {
+            String definingPackageName, int definingUid, String definingProcessName,
+            String triggerType) {
         this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE, definingPackageName,
                 definingUid, false /* isTopApp */, definingProcessName, null /* action */,
-                TRIGGER_TYPE_UNKNOWN);
+                triggerType);
     }
 
     public HostingRecord(@NonNull String hostingType, ComponentName hostingName, boolean isTopApp) {
@@ -313,9 +316,11 @@
             case TRIGGER_TYPE_ALARM:
                 return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_ALARM;
             case TRIGGER_TYPE_PUSH_MESSAGE:
-                return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE;
+                return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE;
             case TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA:
-                return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_PUSH_MESSAGE_OVER_QUOTA;
+                return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA;
+            case TRIGGER_TYPE_JOB:
+                return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_JOB;
             default:
                 return PROCESS_START_TIME__TRIGGER_TYPE__TRIGGER_TYPE_UNKNOWN;
         }
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 15887f0..da209f0 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -37,3 +37,7 @@
 per-file CarUserSwitchingDialog.java = file:platform/packages/services/Car:/OWNERS
 
 per-file ContentProviderHelper.java = [email protected], [email protected], [email protected], [email protected]
+
+# Multiuser
+per-file User* = file:/MULTIUSER_OWNERS
+
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 12aa66b..dbe80c8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -305,7 +305,7 @@
      */
     private final Handler mProcessGroupHandler;
 
-    private final ArraySet<BroadcastQueue> mTmpBroadcastQueue = new ArraySet();
+    private final int[] mTmpSchedGroup = new int[1];
 
     private final ActivityManagerService mService;
     private final ProcessList mProcessList;
@@ -1677,14 +1677,13 @@
             if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
                 reportOomAdjMessageLocked(TAG_OOM_ADJ, "Making instrumentation: " + app);
             }
-        } else if (state.getCachedIsReceivingBroadcast(mTmpBroadcastQueue)) {
+        } else if (state.getCachedIsReceivingBroadcast(mTmpSchedGroup)) {
             // An app that is currently receiving a broadcast also
             // counts as being in the foreground for OOM killer purposes.
             // It's placed in a sched group based on the nature of the
             // broadcast as reflected by which queue it's active in.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = (mTmpBroadcastQueue.contains(mService.mFgBroadcastQueue))
-                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+            schedGroup = mTmpSchedGroup[0];
             state.setAdjType("broadcast");
             procState = ActivityManager.PROCESS_STATE_RECEIVER;
             if (DEBUG_OOM_ADJ_REASON || logUid == appUid) {
@@ -2535,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
@@ -2557,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:
@@ -2566,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 ccbca76..992d416 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -133,8 +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.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.wm.ActivityServiceConnectionsHolder;
 import com.android.server.wm.WindowManagerService;
@@ -277,6 +276,8 @@
     // Memory pages are 4K.
     static final int PAGE_SIZE = 4 * 1024;
 
+    // Activity manager's version of an undefined schedule group
+    static final int SCHED_GROUP_UNDEFINED = Integer.MIN_VALUE;
     // Activity manager's version of Process.THREAD_GROUP_BACKGROUND
     static final int SCHED_GROUP_BACKGROUND = 0;
       // Activity manager's version of Process.THREAD_GROUP_RESTRICTED
@@ -814,12 +815,14 @@
                                                 < LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
                                             return false;
                                         }
-                                        Pair<Integer, Integer> temp = getNumForegroundServices();
-                                        final int totalForegroundServices = temp.first;
-                                        final int procsWithForegroundServices = temp.second;
+                                        // Note: directly access
+                                        // ActiveServices.sNumForegroundServices, do not try to
+                                        // hold AMS lock here, otherwise it is a potential deadlock.
+                                        Pair<Integer, Integer> foregroundServices =
+                                                ActiveServices.sNumForegroundServices.get();
                                         LmkdStatsReporter.logKillOccurred(inputData,
-                                                totalForegroundServices,
-                                                procsWithForegroundServices);
+                                                foregroundServices.first,
+                                                foregroundServices.second);
                                         return true;
                                     case LMK_STATE_CHANGED:
                                         if (receivedLen
@@ -1790,14 +1793,6 @@
 
             if (app.info.isEmbeddedDexUsed()) {
                 runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
-            } else if (app.info.isPrivilegedApp()) {
-                final PackageList pkgList = app.getPkgList();
-                synchronized (pkgList) {
-                    if (DexManager.isPackageSelectedToRunOob(
-                            pkgList.getPackageListLocked().keySet())) {
-                        runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES;
-                    }
-                }
             }
 
             if (!disableHiddenApiChecks && !mService.mHiddenApiBlacklist.isDisabled()) {
@@ -2205,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);
 
@@ -2240,7 +2244,7 @@
                 bindMountAppsData = false;
             }
 
-            if (!hasAppStorage) {
+            if (!hasAppStorage && !app.isSdkSandbox) {
                 bindMountAppsData = false;
                 pkgDataInfoMap = null;
                 allowlistedAppDataInfoMap = null;
@@ -3649,7 +3653,14 @@
         if (thread == null) {
             return null;
         }
-        final IBinder threadBinder = thread.asBinder();
+        return getLRURecordForAppLOSP(thread.asBinder());
+    }
+
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    ProcessRecord getLRURecordForAppLOSP(IBinder threadBinder) {
+        if (threadBinder == null) {
+            return null;
+        }
         // Find the application record.
         for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
             final ProcessRecord rec = mLruProcesses.get(i);
@@ -3733,6 +3744,10 @@
                 ActivityManager.RunningAppProcessInfo currApp =
                         new ActivityManager.RunningAppProcessInfo(app.processName,
                                 app.getPid(), app.getPackageList());
+                if (app.getPkgDeps() != null) {
+                    final int size = app.getPkgDeps().size();
+                    currApp.pkgDeps = app.getPkgDeps().toArray(new String[size]);
+                }
                 fillInProcMemInfoLOSP(app, currApp, clientTargetSdk);
                 if (state.getAdjSource() instanceof ProcessRecord) {
                     currApp.importanceReasonPid = ((ProcessRecord) state.getAdjSource()).getPid();
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index eb1fd3a..ef13778 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -30,7 +30,6 @@
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.os.SystemClock;
-import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
 
@@ -1071,14 +1070,12 @@
     }
 
     @GuardedBy("mService")
-    boolean getCachedIsReceivingBroadcast(ArraySet<BroadcastQueue> tmpQueue) {
+    boolean getCachedIsReceivingBroadcast(int[] outSchedGroup) {
         if (mCachedIsReceivingBroadcast == VALUE_INVALID) {
-            tmpQueue.clear();
-            mCachedIsReceivingBroadcast = mService.isReceivingBroadcastLocked(mApp, tmpQueue)
+            mCachedIsReceivingBroadcast = mService.isReceivingBroadcastLocked(mApp, outSchedGroup)
                     ? VALUE_TRUE : VALUE_FALSE;
             if (mCachedIsReceivingBroadcast == VALUE_TRUE) {
-                mCachedSchedGroup = tmpQueue.contains(mService.mFgBroadcastQueue)
-                        ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
+                mCachedSchedGroup = outSchedGroup[0];
                 mApp.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER);
             } else {
                 mApp.mProfile.clearHostingComponentType(HOSTING_COMPONENT_TYPE_BROADCAST_RECEIVER);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a1f3dae..1954f76 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1036,7 +1036,13 @@
         if (uss.state != UserState.STATE_STOPPING
                 && uss.state != UserState.STATE_SHUTDOWN) {
             uss.setState(UserState.STATE_STOPPING);
-            mInjector.getUserManagerInternal().setUserState(userId, uss.state);
+            UserManagerInternal userManagerInternal = mInjector.getUserManagerInternal();
+            userManagerInternal.setUserState(userId, uss.state);
+            // TODO(b/239982558): for now we're just updating the user's visibility, but most likely
+            // we'll need to remove this call and handle that as part of the user state workflow
+            // instead.
+            userManagerInternal.unassignUserFromDisplay(userId);
+
             updateStartedUserArrayLU();
 
             final boolean allowDelayedLockingCopied = allowDelayedLocking;
@@ -1076,12 +1082,6 @@
                         Binder.getCallingPid(), UserHandle.USER_ALL);
             });
         }
-
-        // TODO(b/239982558): for now we're just updating the user's visibility, but most likely
-        // we'll need to remove this call and handle that as part of the user state workflow
-        // instead.
-        // TODO(b/240613396) also check if multi-display is supported
-        mInjector.getUserManagerInternal().assignUserToDisplay(userId, Display.INVALID_DISPLAY);
     }
 
     private void finishUserStopping(final int userId, final UserState uss,
@@ -1375,8 +1375,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) {
@@ -1391,7 +1392,6 @@
                 && !user.isQuietModeEnabled();
     }
 
-    // TODO(b/239982558): might need to infer the display id based on parent user
     /**
      * Starts a user only if it's a profile, with a more relaxed permission requirement:
      * {@link android.Manifest.permission#MANAGE_USERS} or
@@ -1420,7 +1420,10 @@
             return false;
         }
 
-        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,17 +1475,17 @@
 
     // 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);
 
-        // DEFAULT_DISPLAY is used for "regular" start user operations
+        // DEFAULT_DISPLAY is used for the current foreground user only
         Preconditions.checkArgument(displayId != Display.DEFAULT_DISPLAY,
                 "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;
@@ -1510,27 +1513,11 @@
                     foreground ? " in foreground" : "");
         }
 
-        // TODO(b/239982558): move logic below to a different class (like DisplayAssignmentManager)
         if (displayId != Display.DEFAULT_DISPLAY) {
-            // This is called by startUserOnSecondaryDisplay()
-            if (!UserManager.isUsersOnSecondaryDisplaysEnabled()) {
-                // TODO(b/239824814): add CTS test and/or unit test for all exceptional cases
-                throw new UnsupportedOperationException("Not supported by device");
-            }
-
-            // 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 start system user"
-                    + " on secondary display (%d)", displayId);
             Preconditions.checkArgument(!foreground, "Cannot start user %d in foreground AND "
                     + "on secondary display (%d)", userId, displayId);
-
-            // TODO(b/239982558): for now we're just updating the user's visibility, but most likely
-            // we'll need to remove this call and handle that as part of the user state workflow
-            // instead.
-            mInjector.getUserManagerInternal().assignUserToDisplay(userId, displayId);
         }
-
+        // TODO(b/239982558): log display id (or use a new event)
         EventLog.writeEvent(EventLogTags.UC_START_USER_INTERNAL, userId);
 
         final int callingUid = Binder.getCallingUid();
@@ -1585,6 +1572,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");
@@ -3498,5 +3487,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/ambientcontext/AmbientContextManagerPerUserService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
index de70fa0..dcadd5f 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerPerUserService.java
@@ -29,6 +29,7 @@
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
 import android.app.ambientcontext.AmbientContextManager;
+import android.app.ambientcontext.IAmbientContextObserver;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
@@ -53,6 +54,8 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * Per-user manager service for {@link AmbientContextEvent}s.
@@ -165,20 +168,17 @@
      * package. A new registration from the same package will overwrite the previous registration.
      */
     public void onRegisterObserver(AmbientContextEventRequest request,
-            PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
+            String packageName, IAmbientContextObserver observer) {
         synchronized (mLock) {
             if (!setUpServiceIfNeeded()) {
                 Slog.w(TAG, "Detection service is not available at this moment.");
-                sendStatusCallback(
-                        clientStatusCallback,
-                        AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
+                completeRegistration(observer, AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
                 return;
             }
 
             // Register package and add to existing ClientRequests cache
-            startDetection(request, pendingIntent.getCreatorPackage(),
-                    createDetectionResultRemoteCallback(), clientStatusCallback);
-            mMaster.newClientAdded(mUserId, request, pendingIntent, clientStatusCallback);
+            startDetection(request, packageName, observer);
+            mMaster.newClientAdded(mUserId, request, packageName, observer);
         }
     }
 
@@ -186,49 +186,46 @@
      * Returns a RemoteCallback that handles the status from the detection service, and
      * sends results to the client callback.
      */
-    private RemoteCallback getServerStatusCallback(RemoteCallback clientStatusCallback) {
+    private RemoteCallback getServerStatusCallback(Consumer<Integer> statusConsumer) {
         return new RemoteCallback(result -> {
             AmbientContextDetectionServiceStatus serviceStatus =
                     (AmbientContextDetectionServiceStatus) result.get(
                             AmbientContextDetectionServiceStatus.STATUS_RESPONSE_BUNDLE_KEY);
             final long token = Binder.clearCallingIdentity();
             try {
-                String packageName = serviceStatus.getPackageName();
-                Bundle bundle = new Bundle();
-                bundle.putInt(
-                        AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
-                        serviceStatus.getStatusCode());
-                clientStatusCallback.sendResult(bundle);
                 int statusCode = serviceStatus.getStatusCode();
+                statusConsumer.accept(statusCode);
                 Slog.i(TAG, "Got detection status of " + statusCode
-                        + " for " + packageName);
+                        + " for " + serviceStatus.getPackageName());
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
         });
     }
 
-    @VisibleForTesting
     void startDetection(AmbientContextEventRequest request, String callingPackage,
-            RemoteCallback detectionResultCallback, RemoteCallback clientStatusCallback) {
+            IAmbientContextObserver observer) {
         Slog.d(TAG, "Requested detection of " + request.getEventTypes());
         synchronized (mLock) {
             if (setUpServiceIfNeeded()) {
                 ensureRemoteServiceInitiated();
-                mRemoteService.startDetection(request, callingPackage, detectionResultCallback,
-                        getServerStatusCallback(clientStatusCallback));
+                mRemoteService.startDetection(request, callingPackage,
+                        createDetectionResultRemoteCallback(),
+                        getServerStatusCallback(
+                                statusCode -> completeRegistration(observer, statusCode)));
             } else {
                 Slog.w(TAG, "No valid component found for AmbientContextDetectionService");
-                sendStatusToCallback(clientStatusCallback,
-                        AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
+                completeRegistration(observer,
+                        AmbientContextManager.STATUS_NOT_SUPPORTED);
             }
         }
     }
 
     /**
-     * Sends an intent with a status code and empty events.
+     * Sends the result response with the specified status to the callback.
      */
-    void sendStatusCallback(RemoteCallback statusCallback, int statusCode) {
+    static void sendStatusCallback(RemoteCallback statusCallback,
+            @AmbientContextManager.StatusCode int statusCode) {
         Bundle bundle = new Bundle();
         bundle.putInt(
                 AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
@@ -236,6 +233,15 @@
         statusCallback.sendResult(bundle);
     }
 
+    static void completeRegistration(IAmbientContextObserver observer, int statusCode) {
+        try {
+            observer.onRegistrationComplete(statusCode);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Failed to call IAmbientContextObserver.onRegistrationComplete: "
+                    + e.getMessage());
+        }
+    }
+
     /**
      * Unregisters the client from all previously registered events by removing from the
      * mExistingRequests map, and unregister events from the service if those events are not
@@ -255,7 +261,7 @@
         synchronized (mLock) {
             if (!setUpServiceIfNeeded()) {
                 Slog.w(TAG, "Detection service is not available at this moment.");
-                sendStatusToCallback(statusCallback,
+                sendStatusCallback(statusCallback,
                         AmbientContextManager.STATUS_NOT_SUPPORTED);
                 return;
             }
@@ -263,7 +269,8 @@
             mRemoteService.queryServiceStatus(
                     eventTypes,
                     callingPackage,
-                    getServerStatusCallback(statusCallback));
+                    getServerStatusCallback(
+                            statusCode -> sendStatusCallback(statusCallback, statusCode)));
         }
     }
 
@@ -350,18 +357,6 @@
         return ComponentName.unflattenFromString(consentComponent);
     }
 
-    /**
-     * Sends the result response with the specified status to the callback.
-     */
-    void sendStatusToCallback(RemoteCallback callback,
-                    @AmbientContextManager.StatusCode int status) {
-        Bundle bundle = new Bundle();
-        bundle.putInt(
-                AmbientContextManager.STATUS_RESPONSE_BUNDLE_KEY,
-                status);
-        callback.sendResult(bundle);
-    }
-
     @VisibleForTesting
     void stopDetection(String packageName) {
         Slog.d(TAG, "Stop detection for " + packageName);
@@ -377,13 +372,13 @@
      * Sends out the Intent to the client after the event is detected.
      *
      * @param pendingIntent Client's PendingIntent for callback
-     * @param result result from the detection service
+     * @param events detected events from the detection service
      */
-    private void sendDetectionResultIntent(PendingIntent pendingIntent,
-            AmbientContextDetectionResult result) {
+    void sendDetectionResultIntent(PendingIntent pendingIntent,
+            List<AmbientContextEvent> events) {
         Intent intent = new Intent();
         intent.putExtra(AmbientContextManager.EXTRA_AMBIENT_CONTEXT_EVENTS,
-                new ArrayList(result.getEvents()));
+                new ArrayList(events));
         // Explicitly disallow the receiver from starting activities, to prevent apps from utilizing
         // the PendingIntent as a backdoor to do this.
         BroadcastOptions options = BroadcastOptions.makeBasic();
@@ -392,7 +387,7 @@
             pendingIntent.send(getContext(), 0, intent, null, null, null,
                     options.toBundle());
             Slog.i(TAG, "Sending PendingIntent to " + pendingIntent.getCreatorPackage() + ": "
-                    + result);
+                    + events);
         } catch (PendingIntent.CanceledException e) {
             Slog.w(TAG, "Couldn't deliver pendingIntent:" + pendingIntent);
         }
@@ -405,16 +400,19 @@
                     (AmbientContextDetectionResult) result.get(
                             AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
             String packageName = detectionResult.getPackageName();
-            PendingIntent pendingIntent = mMaster.getPendingIntent(mUserId, packageName);
-            if (pendingIntent == null) {
+            IAmbientContextObserver observer = mMaster.getClientRequestObserver(
+                    mUserId, packageName);
+            if (observer == null) {
                 return;
             }
 
             final long token = Binder.clearCallingIdentity();
             try {
-                sendDetectionResultIntent(pendingIntent, detectionResult);
+                observer.onEvents(detectionResult.getEvents());
                 Slog.i(TAG, "Got detection result of " + detectionResult.getEvents()
                         + " for " + packageName);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to call IAmbientContextObserver.onEvents: " + e.getMessage());
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 4206262..e205e84 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -27,10 +27,12 @@
 import android.app.ambientcontext.AmbientContextEventRequest;
 import android.app.ambientcontext.AmbientContextManager;
 import android.app.ambientcontext.IAmbientContextManager;
+import android.app.ambientcontext.IAmbientContextObserver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
 import android.os.RemoteCallback;
+import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
 import android.os.UserHandle;
@@ -48,6 +50,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -67,31 +70,27 @@
     static class ClientRequest {
         private final int mUserId;
         private final AmbientContextEventRequest mRequest;
-        private final PendingIntent mPendingIntent;
-        private final RemoteCallback mClientStatusCallback;
+        private final String mPackageName;
+        private final IAmbientContextObserver mObserver;
 
         ClientRequest(int userId, AmbientContextEventRequest request,
-                PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
+                String packageName, IAmbientContextObserver observer) {
             this.mUserId = userId;
             this.mRequest = request;
-            this.mPendingIntent = pendingIntent;
-            this.mClientStatusCallback = clientStatusCallback;
+            this.mPackageName = packageName;
+            this.mObserver = observer;
         }
 
         String getPackageName() {
-            return mPendingIntent.getCreatorPackage();
+            return mPackageName;
         }
 
         AmbientContextEventRequest getRequest() {
             return mRequest;
         }
 
-        PendingIntent getPendingIntent() {
-            return mPendingIntent;
-        }
-
-        RemoteCallback getClientStatusCallback() {
-            return mClientStatusCallback;
+        IAmbientContextObserver getObserver() {
+            return mObserver;
         }
 
         boolean hasUserId(int userId) {
@@ -139,16 +138,16 @@
     }
 
     void newClientAdded(int userId, AmbientContextEventRequest request,
-            PendingIntent pendingIntent, RemoteCallback clientStatusCallback) {
-        Slog.d(TAG, "New client added: " + pendingIntent.getCreatorPackage());
+            String callingPackage, IAmbientContextObserver observer) {
+        Slog.d(TAG, "New client added: " + callingPackage);
 
         // Remove any existing ClientRequest for this user and package.
         mExistingClientRequests.removeAll(
-                findExistingRequests(userId, pendingIntent.getCreatorPackage()));
+                findExistingRequests(userId, callingPackage));
 
         // Add to existing ClientRequests
         mExistingClientRequests.add(
-                new ClientRequest(userId, request, pendingIntent, clientStatusCallback));
+                new ClientRequest(userId, request, callingPackage, observer));
     }
 
     void clientRemoved(int userId, String packageName) {
@@ -167,10 +166,10 @@
     }
 
     @Nullable
-    PendingIntent getPendingIntent(int userId, String packageName) {
+    IAmbientContextObserver getClientRequestObserver(int userId, String packageName) {
         for (ClientRequest clientRequest : mExistingClientRequests) {
             if (clientRequest.hasUserIdAndPackageName(userId, packageName)) {
-                return clientRequest.getPendingIntent();
+                return clientRequest.getObserver();
             }
         }
         return null;
@@ -236,15 +235,13 @@
      * Requires ACCESS_AMBIENT_CONTEXT_EVENT permission.
      */
     void startDetection(@UserIdInt int userId, AmbientContextEventRequest request,
-            String packageName, RemoteCallback detectionResultCallback,
-            RemoteCallback statusCallback) {
+            String packageName, IAmbientContextObserver observer) {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
         synchronized (mLock) {
             final AmbientContextManagerPerUserService service = getServiceForUserLocked(userId);
             if (service != null) {
-                service.startDetection(request, packageName, detectionResultCallback,
-                        statusCallback);
+                service.startDetection(request, packageName, observer);
             } else {
                 Slog.i(TAG, "service not available for user_id: " + userId);
             }
@@ -297,8 +294,7 @@
                     Slog.d(TAG, "Restoring detection for " + clientRequest.getPackageName());
                     service.startDetection(clientRequest.getRequest(),
                             clientRequest.getPackageName(),
-                            service.createDetectionResultRemoteCallback(),
-                            clientRequest.getClientStatusCallback());
+                            clientRequest.getObserver());
                 }
             }
         }
@@ -328,16 +324,45 @@
             Objects.requireNonNull(request);
             Objects.requireNonNull(resultPendingIntent);
             Objects.requireNonNull(statusCallback);
+            // Wrap the PendingIntent and statusCallback in a IAmbientContextObserver to make the
+            // code unified
+            IAmbientContextObserver observer = new IAmbientContextObserver.Stub() {
+                @Override
+                public void onEvents(List<AmbientContextEvent> events) throws RemoteException {
+                    mService.sendDetectionResultIntent(resultPendingIntent, events);
+                }
+
+                @Override
+                public void onRegistrationComplete(int statusCode) throws RemoteException {
+                    AmbientContextManagerPerUserService.sendStatusCallback(statusCallback,
+                            statusCode);
+                }
+            };
+            registerObserverWithCallback(request, resultPendingIntent.getCreatorPackage(),
+                    observer);
+        }
+
+        /**
+         * Register an observer for Ambient Context events.
+         */
+        @Override
+        public void registerObserverWithCallback(AmbientContextEventRequest request,
+                String packageName,
+                IAmbientContextObserver observer) {
+            Slog.i(TAG, "AmbientContextManagerService registerObserverWithCallback.");
+            Objects.requireNonNull(request);
+            Objects.requireNonNull(packageName);
+            Objects.requireNonNull(observer);
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.ACCESS_AMBIENT_CONTEXT_EVENT, TAG);
-            assertCalledByPackageOwner(resultPendingIntent.getCreatorPackage());
+            assertCalledByPackageOwner(packageName);
             if (!mIsServiceEnabled) {
                 Slog.w(TAG, "Service not available.");
-                mService.sendStatusCallback(statusCallback,
+                AmbientContextManagerPerUserService.completeRegistration(observer,
                         AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
                 return;
             }
-            mService.onRegisterObserver(request, resultPendingIntent, statusCallback);
+            mService.onRegisterObserver(request, packageName, observer);
         }
 
         @Override
@@ -359,7 +384,7 @@
             assertCalledByPackageOwner(callingPackage);
             if (!mIsServiceEnabled) {
                 Slog.w(TAG, "Detection service not available.");
-                mService.sendStatusToCallback(statusCallback,
+                AmbientContextManagerPerUserService.sendStatusCallback(statusCallback,
                         AmbientContextManager.STATUS_SERVICE_UNAVAILABLE);
                 return;
             }
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
index ec6c2f0..a3ffcde8 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextShellCommand.java
@@ -22,13 +22,15 @@
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
 import android.app.ambientcontext.AmbientContextManager;
+import android.app.ambientcontext.IAmbientContextObserver;
 import android.content.ComponentName;
 import android.os.Binder;
 import android.os.RemoteCallback;
+import android.os.RemoteException;
 import android.os.ShellCommand;
-import android.service.ambientcontext.AmbientContextDetectionResult;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 /**
  * Shell command for {@link AmbientContextManagerService}.
@@ -39,6 +41,7 @@
             new AmbientContextEventRequest.Builder()
                     .addEventType(AmbientContextEvent.EVENT_COUGH)
                     .addEventType(AmbientContextEvent.EVENT_SNORE)
+                    .addEventType(AmbientContextEvent.EVENT_BACK_DOUBLE_TAP)
                     .build();
 
     @NonNull
@@ -50,11 +53,11 @@
 
     /** Callbacks for AmbientContextEventService results used internally for testing. */
     static class TestableCallbackInternal {
-        private AmbientContextDetectionResult mLastResult;
+        private List<AmbientContextEvent> mLastEvents;
         private int mLastStatus;
 
-        public AmbientContextDetectionResult getLastResult() {
-            return mLastResult;
+        public List<AmbientContextEvent> getLastEvents() {
+            return mLastEvents;
         }
 
         public int getLastStatus() {
@@ -62,19 +65,19 @@
         }
 
         @NonNull
-        private RemoteCallback createRemoteDetectionResultCallback() {
-            return new RemoteCallback(result -> {
-                AmbientContextDetectionResult detectionResult =
-                        (AmbientContextDetectionResult) result.get(
-                                AmbientContextDetectionResult.RESULT_RESPONSE_BUNDLE_KEY);
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    mLastResult = detectionResult;
-                    out.println("Detection result available: " + detectionResult);
-                } finally {
-                    Binder.restoreCallingIdentity(token);
+        private IAmbientContextObserver createAmbientContextObserver() {
+            return new IAmbientContextObserver.Stub() {
+                @Override
+                public void onEvents(List<AmbientContextEvent> events) throws RemoteException {
+                    mLastEvents = events;
+                    out.println("Detection events available: " + events);
                 }
-            });
+
+                @Override
+                public void onRegistrationComplete(int statusCode) throws RemoteException {
+                    mLastStatus = statusCode;
+                }
+            };
         }
 
         @NonNull
@@ -123,8 +126,7 @@
         final String packageName = getNextArgRequired();
         mService.startDetection(
                 userId, REQUEST, packageName,
-                sTestableCallbackInternal.createRemoteDetectionResultCallback(),
-                sTestableCallbackInternal.createRemoteStatusCallback());
+                sTestableCallbackInternal.createAmbientContextObserver());
         return 0;
     }
 
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 248e35e..62ae9b8 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -177,7 +177,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;
 
@@ -267,6 +267,10 @@
             OP_CAMERA,
     };
 
+    private static final int[] WATCHABLE_NON_PERMISSION_OPS = {
+            OP_RECEIVE_AMBIENT_TRIGGER_AUDIO,
+    };
+
     private static final int MAX_UNFORWARDED_OPS = 10;
     private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
     private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
@@ -574,7 +578,7 @@
             mAppOpsServiceInterface.removeUid(uid);
             if (pkgOps != null) {
                 for (String packageName : pkgOps.keySet()) {
-                    mAppOpsServiceInterface.removePackage(packageName);
+                    mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
                 }
             }
             pkgOps = null;
@@ -584,7 +588,8 @@
             boolean areAllPackageModesDefault = true;
             if (pkgOps != null) {
                 for (String packageName : pkgOps.keySet()) {
-                    if (!mAppOpsServiceInterface.arePackageModesDefault(packageName)) {
+                    if (!mAppOpsServiceInterface.arePackageModesDefault(packageName,
+                            UserHandle.getUserId(uid))) {
                         areAllPackageModesDefault = false;
                         break;
                     }
@@ -664,7 +669,8 @@
             if (pkgOps != null) {
                 for (int i = pkgOps.size() - 1; i >= 0; i--) {
                     foregroundOps = mAppOpsServiceInterface
-                            .evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps);
+                            .evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps,
+                                    UserHandle.getUserId(uid));
                 }
             }
             hasForegroundWatchers = false;
@@ -1467,10 +1473,12 @@
         }
 
         @Mode int getMode() {
-            return mAppOpsServiceInterface.getPackageMode(packageName, this.op);
+            return mAppOpsServiceInterface.getPackageMode(packageName, this.op,
+                    UserHandle.getUserId(this.uid));
         }
         void setMode(@Mode int mode) {
-            mAppOpsServiceInterface.setPackageMode(packageName, this.op, mode);
+            mAppOpsServiceInterface.setPackageMode(packageName, this.op, mode,
+                    UserHandle.getUserId(this.uid));
         }
 
         int evalMode() {
@@ -1814,7 +1822,7 @@
                     if (uidState == null || uidState.pkgOps == null) {
                         return;
                     }
-                    mAppOpsServiceInterface.removePackage(pkgName);
+                    mAppOpsServiceInterface.removePackage(pkgName, UserHandle.getUserId(uid));
                     Ops removedOps = uidState.pkgOps.remove(pkgName);
                     if (removedOps != null) {
                         scheduleFastWriteLocked();
@@ -2041,7 +2049,7 @@
             // Remove any package state if such.
             if (uidState.pkgOps != null) {
                 removedOps = uidState.pkgOps.remove(packageName);
-                mAppOpsServiceInterface.removePackage(packageName);
+                mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
             }
 
             // If we just nuked the last package state check if the UID is valid.
@@ -2491,7 +2499,8 @@
                     ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
                     if (pkgOps != null) {
                         pkgOps.remove(ops.packageName);
-                        mAppOpsServiceInterface.removePackage(ops.packageName);
+                        mAppOpsServiceInterface.removePackage(ops.packageName,
+                                UserHandle.getUserId(uidState.uid));
                         if (pkgOps.isEmpty()) {
                             uidState.pkgOps = null;
                         }
@@ -2944,7 +2953,8 @@
                     }
                     if (pkgOps.size() == 0) {
                         it.remove();
-                        mAppOpsServiceInterface.removePackage(packageName);
+                        mAppOpsServiceInterface.removePackage(packageName,
+                                UserHandle.getUserId(uidState.uid));
                     }
                 }
                 if (uidState.isDefault()) {
@@ -4242,6 +4252,10 @@
     public boolean shouldCollectNotes(int opCode) {
         Preconditions.checkArgumentInRange(opCode, 0, _NUM_OP - 1, "opCode");
 
+        if (ArrayUtils.contains(WATCHABLE_NON_PERMISSION_OPS, opCode)) {
+            return true;
+        }
+
         String perm = AppOpsManager.opToPermission(opCode);
         if (perm == null) {
             return false;
@@ -6646,7 +6660,7 @@
                 return;
             }
             Ops removedOps = uidState.pkgOps.remove(packageName);
-            mAppOpsServiceInterface.removePackage(packageName);
+            mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
             if (removedOps != null) {
                 scheduleFastWriteLocked();
             }
diff --git a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
index c707086..c4a9a4b 100644
--- a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
+++ b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
@@ -17,6 +17,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AppOpsManager.Mode;
 import android.util.ArraySet;
 import android.util.SparseBooleanArray;
@@ -61,23 +62,27 @@
      * Returns default op mode if the op mode for the particular package is not set.
      * @param packageName package name for which we need the op mode.
      * @param op app-op for which we need the mode.
+     * @param userId user id associated with the package.
      * @return the mode of the app-op.
      */
-    int getPackageMode(@NonNull String packageName, int op);
+    int getPackageMode(@NonNull String packageName, int op, @UserIdInt int userId);
 
     /**
      * Sets the app-op mode for a particular package.
      * @param packageName package name for which we need to set the op mode.
      * @param op app-op for which we need to set the mode.
      * @param mode the mode of the app-op.
+     * @param userId user id associated with the package.
+     *
      */
-    void setPackageMode(@NonNull String packageName, int op, @Mode int mode);
+    void setPackageMode(@NonNull String packageName, int op, @Mode int mode, @UserIdInt int userId);
 
     /**
      * Stop tracking any app-op modes for a package.
      * @param packageName Name of the package for which we want to remove all mode tracking.
+     * @param userId user id associated with the package.
      */
-    boolean removePackage(@NonNull String packageName);
+    boolean removePackage(@NonNull String packageName,  @UserIdInt int userId);
 
     /**
      * Stop tracking any app-op modes for this uid.
@@ -96,8 +101,9 @@
      * Returns true if all package modes for this package name are
      * in default state.
      * @param packageName package name.
+     * @param userId user id associated with the package.
      */
-    boolean arePackageModesDefault(String packageName);
+    boolean arePackageModesDefault(String packageName, @UserIdInt int userId);
 
     /**
      * Stop tracking app-op modes for all uid and packages.
@@ -177,10 +183,11 @@
      * foregroundOps.
      * @param packageName for which the app-op's mode needs to be marked.
      * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
+     * @param userId user id associated with the package.
      * @return foregroundOps.
      */
     SparseBooleanArray evalForegroundPackageOps(String packageName,
-            SparseBooleanArray foregroundOps);
+            SparseBooleanArray foregroundOps, @UserIdInt int userId);
 
     /**
      * Dump op mode and package mode listeners and their details.
diff --git a/services/core/java/com/android/server/appop/DiscreteRegistry.java b/services/core/java/com/android/server/appop/DiscreteRegistry.java
index 158092f..dd0c4b86 100644
--- a/services/core/java/com/android/server/appop/DiscreteRegistry.java
+++ b/services/core/java/com/android/server/appop/DiscreteRegistry.java
@@ -816,8 +816,7 @@
 
                     }
                 } catch (Throwable t) {
-                    Slog.e(TAG, "Error while cleaning timeline files: " + t.getMessage() + " "
-                            + t.getStackTrace());
+                    Slog.e(TAG, "Error while cleaning timeline files: ", t);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
index 2d498ea..80266972 100644
--- a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
+++ b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
@@ -25,6 +25,7 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.Mode;
@@ -70,7 +71,7 @@
     final SparseArray<SparseIntArray> mUidModes = new SparseArray<>();
 
     @GuardedBy("mLock")
-    final ArrayMap<String, SparseIntArray> mPackageModes = new ArrayMap<>();
+    final SparseArray<ArrayMap<String, SparseIntArray>> mUserPackageModes = new SparseArray<>();
 
     final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>();
     final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers =
@@ -147,9 +148,13 @@
     }
 
     @Override
-    public int getPackageMode(String packageName, int op) {
+    public int getPackageMode(String packageName, int op, @UserIdInt int userId) {
         synchronized (mLock) {
-            SparseIntArray opModes = mPackageModes.getOrDefault(packageName, null);
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                return AppOpsManager.opToDefaultMode(op);
+            }
+            SparseIntArray opModes = packageModes.getOrDefault(packageName, null);
             if (opModes == null) {
                 return AppOpsManager.opToDefaultMode(op);
             }
@@ -158,14 +163,19 @@
     }
 
     @Override
-    public void setPackageMode(String packageName, int op, @Mode int mode) {
+    public void setPackageMode(String packageName, int op, @Mode int mode, @UserIdInt int userId) {
         final int defaultMode = AppOpsManager.opToDefaultMode(op);
         synchronized (mLock) {
-            SparseIntArray opModes = mPackageModes.get(packageName);
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                packageModes = new ArrayMap<>();
+                mUserPackageModes.put(userId, packageModes);
+            }
+            SparseIntArray opModes = packageModes.get(packageName);
             if (opModes == null) {
                 if (mode != defaultMode) {
                     opModes = new SparseIntArray();
-                    mPackageModes.put(packageName, opModes);
+                    packageModes.put(packageName, opModes);
                     opModes.put(op, mode);
                     mPersistenceScheduler.scheduleWriteLocked();
                 }
@@ -177,7 +187,7 @@
                     opModes.delete(op);
                     if (opModes.size() <= 0) {
                         opModes = null;
-                        mPackageModes.remove(packageName);
+                        packageModes.remove(packageName);
                     }
                 } else {
                     opModes.put(op, mode);
@@ -208,17 +218,25 @@
     }
 
     @Override
-    public boolean arePackageModesDefault(String packageMode) {
+    public boolean arePackageModesDefault(String packageMode, @UserIdInt int userId) {
         synchronized (mLock) {
-            SparseIntArray opModes = mPackageModes.get(packageMode);
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                return true;
+            }
+            SparseIntArray opModes = packageModes.get(packageMode);
             return (opModes == null || opModes.size() <= 0);
         }
     }
 
     @Override
-    public boolean removePackage(String packageName) {
+    public boolean removePackage(String packageName, @UserIdInt int userId) {
         synchronized (mLock) {
-            SparseIntArray ops = mPackageModes.remove(packageName);
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                return false;
+            }
+            SparseIntArray ops = packageModes.remove(packageName);
             if (ops != null) {
                 mPersistenceScheduler.scheduleFastWriteLocked();
                 return true;
@@ -231,7 +249,7 @@
     public void clearAllModes() {
         synchronized (mLock) {
             mUidModes.clear();
-            mPackageModes.clear();
+            mUserPackageModes.clear();
         }
     }
 
@@ -468,9 +486,11 @@
 
     @Override
     public SparseBooleanArray evalForegroundPackageOps(String packageName,
-            SparseBooleanArray foregroundOps) {
+            SparseBooleanArray foregroundOps, @UserIdInt int userId) {
         synchronized (mLock) {
-            return evalForegroundOps(mPackageModes.get(packageName), foregroundOps);
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            return evalForegroundOps(packageModes == null ? null : packageModes.get(packageName),
+                    foregroundOps);
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 785040e..31f8659 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1010,7 +1010,9 @@
 
         mSfxHelper = new SoundEffectsHelper(mContext);
 
-        mSpatializerHelper = new SpatializerHelper(this, mAudioSystem);
+        final boolean headTrackingDefault = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_spatial_audio_head_tracking_enabled_default);
+        mSpatializerHelper = new SpatializerHelper(this, mAudioSystem, headTrackingDefault);
 
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
@@ -3358,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) {
@@ -4115,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) {
@@ -6955,7 +6955,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;
@@ -7722,7 +7723,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;
@@ -7744,7 +7747,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;
@@ -8165,7 +8169,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 66a4527..6e85361 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -53,8 +53,6 @@
 
     private static final String TAG = "AS.BtHelper";
 
-    private static final int SOURCE_CODEC_TYPE_OPUS = 6; // TODO remove in U
-
     private final @NonNull AudioDeviceBroker mDeviceBroker;
 
     BtHelper(@NonNull AudioDeviceBroker broker) {
@@ -412,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="
@@ -913,7 +910,7 @@
                 return "ENCODING_APTX_HD";
             case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
                 return "ENCODING_LDAC";
-            case SOURCE_CODEC_TYPE_OPUS: // TODO update in U
+            case BluetoothCodecConfig.SOURCE_CODEC_TYPE_OPUS:
                 return "ENCODING_OPUS";
             default:
                 return "ENCODING_BT_CODEC_TYPE(" + btCodecType + ")";
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 4559c56..454894e 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());
         }
     }
 
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index b7e817e..8e8fd05 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -169,9 +169,20 @@
 
     //------------------------------------------------------
     // initialization
-    SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa) {
+    @SuppressWarnings("StaticAssignmentInConstructor")
+    SpatializerHelper(@NonNull AudioService mother, @NonNull AudioSystemAdapter asa,
+            boolean headTrackingEnabledByDefault) {
         mAudioService = mother;
         mASA = asa;
+        // "StaticAssignmentInConstructor" warning is suppressed as the SpatializerHelper being
+        // constructed here is the factory for SADeviceState, thus SADeviceState and its
+        // private static field sHeadTrackingEnabledDefault should never be accessed directly.
+        SADeviceState.sHeadTrackingEnabledDefault = headTrackingEnabledByDefault;
+    }
+
+    synchronized void initForTest(boolean hasBinaural, boolean hasTransaural) {
+        mBinauralSupported = hasBinaural;
+        mTransauralSupported = hasTransaural;
     }
 
     synchronized void init(boolean effectExpected, @Nullable String settings) {
@@ -1115,6 +1126,9 @@
                 && ROUTING_DEVICES[0].getAddress().equals(ada.getAddress())) {
             setDesiredHeadTrackingMode(enabled ? mDesiredHeadTrackingModeWhenEnabled
                     : Spatializer.HEAD_TRACKING_MODE_DISABLED);
+            if (enabled && !mHeadTrackerAvailable) {
+                postInitSensors();
+            }
         }
     }
 
@@ -1499,18 +1513,26 @@
     }
 
     /*package*/ static final class SADeviceState {
+        private static boolean sHeadTrackingEnabledDefault = false;
         final @AudioDeviceInfo.AudioDeviceType int mDeviceType;
         final @NonNull String mDeviceAddress;
         boolean mEnabled = true;               // by default, SA is enabled on any device
         boolean mHasHeadTracker = false;
-        boolean mHeadTrackerEnabled = true;    // by default, if head tracker is present, use it
+        boolean mHeadTrackerEnabled;
         static final String SETTING_FIELD_SEPARATOR = ",";
         static final String SETTING_DEVICE_SEPARATOR_CHAR = "|";
         static final String SETTING_DEVICE_SEPARATOR = "\\|";
 
-        SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @NonNull String address) {
+        /**
+         * Constructor
+         * @param deviceType
+         * @param address must be non-null for wireless devices
+         * @throws NullPointerException if a null address is passed for a wireless device
+         */
+        SADeviceState(@AudioDeviceInfo.AudioDeviceType int deviceType, @Nullable String address) {
             mDeviceType = deviceType;
             mDeviceAddress = isWireless(deviceType) ? Objects.requireNonNull(address) : "";
+            mHeadTrackerEnabled = sHeadTrackingEnabledDefault;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java
index 96c5621..76eba16 100644
--- a/services/core/java/com/android/server/backup/BackupUtils.java
+++ b/services/core/java/com/android/server/backup/BackupUtils.java
@@ -30,6 +30,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 public class BackupUtils {
     private static final String TAG = "BackupUtils";
@@ -64,8 +65,9 @@
         }
 
         if (DEBUG) {
-            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
-                    + " device=" + signingInfo.getApkContentsSigners());
+            Slog.v(TAG, "signaturesMatch(): stored="
+                    + storedSigHashes.stream().map(Arrays::toString).collect(Collectors.toList())
+                    + " device=" + Arrays.toString(signingInfo.getApkContentsSigners()));
         }
 
         final int nStored = storedSigHashes.size();
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 689ddd2..c29755a 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -72,7 +72,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.DumpUtils;
 import com.android.server.SystemService;
-import com.android.server.biometrics.sensors.CoexCoordinator;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -951,16 +950,6 @@
             return new ArrayList<>();
         }
 
-        public boolean isAdvancedCoexLogicEnabled(Context context) {
-            return Settings.Secure.getInt(context.getContentResolver(),
-                    CoexCoordinator.SETTING_ENABLE_NAME, 1) != 0;
-        }
-
-        public boolean isCoexFaceNonBypassHapticsDisabled(Context context) {
-            return Settings.Secure.getInt(context.getContentResolver(),
-                    CoexCoordinator.FACE_HAPTIC_DISABLE, 0) != 0;
-        }
-
         public Supplier<Long> getRequestGenerator() {
             final AtomicLong generator = new AtomicLong(0);
             return () -> generator.incrementAndGet();
@@ -992,14 +981,6 @@
                 mEnabledOnKeyguardCallbacks);
         mRequestCounter = mInjector.getRequestGenerator();
 
-        // TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't
-        //  need to depend on context. We can remove this code once the advanced logic is enabled
-        //  by default.
-        CoexCoordinator coexCoordinator = CoexCoordinator.getInstance();
-        coexCoordinator.setAdvancedLogicEnabled(injector.isAdvancedCoexLogicEnabled(context));
-        coexCoordinator.setFaceHapticDisabledWhenNonBypass(
-                injector.isCoexFaceNonBypassHapticsDisabled(context));
-
         try {
             injector.getActivityManagerService().registerUserSwitchObserver(
                     new UserSwitchObserver() {
@@ -1333,7 +1314,5 @@
         pw.println();
         pw.println("CurrentSession: " + mAuthSession);
         pw.println();
-        pw.println("CoexCoordinator: " + CoexCoordinator.getInstance().toString());
-        pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/log/ALSProbe.java b/services/core/java/com/android/server/biometrics/log/ALSProbe.java
new file mode 100644
index 0000000..62f94ed
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/log/ALSProbe.java
@@ -0,0 +1,163 @@
+/*
+ * 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.biometrics.log;
+
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.biometrics.sensors.BaseClientMonitor;
+
+import java.util.concurrent.TimeUnit;
+
+/** Probe for ambient light. */
+final class ALSProbe implements Probe {
+    private static final String TAG = "ALSProbe";
+
+    @Nullable
+    private final SensorManager mSensorManager;
+    @Nullable
+    private final Sensor mLightSensor;
+    @NonNull
+    private final Handler mTimer;
+    @DurationMillisLong
+    private long mMaxSubscriptionTime = -1;
+
+    private boolean mEnabled = false;
+    private boolean mDestroyed = false;
+    private volatile float mLastAmbientLux = -1;
+
+    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            mLastAmbientLux = event.values[0];
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+            // Not used.
+        }
+    };
+
+    /**
+     * Create a probe with a 1-minute max sampling time.
+     *
+     * @param sensorManager Sensor manager
+     */
+    ALSProbe(@NonNull SensorManager sensorManager) {
+        this(sensorManager, new Handler(Looper.getMainLooper()),
+                TimeUnit.MINUTES.toMillis(1));
+    }
+
+    /**
+     * Create a probe with a given max sampling time.
+     *
+     * Note: The max time is a workaround for potential scheduler bugs where
+     * {@link BaseClientMonitor#destroy()} is not called due to an abnormal lifecycle. Clients
+     * should ensure that {@link #disable()} and {@link #destroy()} are called appropriately and
+     * avoid relying on this timeout to unsubscribe from the sensor when it is not needed.
+     *
+     * @param sensorManager Sensor manager
+     * @param handler Timeout handler
+     * @param maxTime The max amount of time to subscribe to events. If this time is exceeded
+     *                {@link #disable()} will be called and no sampling will occur until {@link
+     *                #enable()} is called again.
+     */
+    @VisibleForTesting
+    ALSProbe(@Nullable SensorManager sensorManager, @NonNull Handler handler,
+            @DurationMillisLong long maxTime) {
+        mSensorManager = sensorManager;
+        mLightSensor = sensorManager != null
+                ? sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) : null;
+        mTimer = handler;
+        mMaxSubscriptionTime = maxTime;
+
+        if (mSensorManager == null || mLightSensor == null) {
+            Slog.w(TAG, "No sensor - probe disabled");
+            mDestroyed = true;
+        }
+    }
+
+    @Override
+    public synchronized void enable() {
+        if (!mDestroyed) {
+            enableLightSensorLoggingLocked();
+        }
+    }
+
+    @Override
+    public synchronized void disable() {
+        if (!mDestroyed) {
+            disableLightSensorLoggingLocked();
+        }
+    }
+
+    @Override
+    public synchronized void destroy() {
+        disable();
+        mDestroyed = true;
+    }
+
+    /** The most recent lux reading. */
+    public float getCurrentLux() {
+        return mLastAmbientLux;
+    }
+
+    private void enableLightSensorLoggingLocked() {
+        if (!mEnabled) {
+            mEnabled = true;
+            mLastAmbientLux = -1;
+            mSensorManager.registerListener(mLightSensorListener, mLightSensor,
+                    SensorManager.SENSOR_DELAY_NORMAL);
+            Slog.v(TAG, "Enable ALS: " + mLightSensorListener.hashCode());
+        }
+
+        resetTimerLocked(true /* start */);
+    }
+
+    private void disableLightSensorLoggingLocked() {
+        resetTimerLocked(false /* start */);
+
+        if (mEnabled) {
+            mEnabled = false;
+            mLastAmbientLux = -1;
+            mSensorManager.unregisterListener(mLightSensorListener);
+            Slog.v(TAG, "Disable ALS: " + mLightSensorListener.hashCode());
+        }
+    }
+
+    private void resetTimerLocked(boolean start) {
+        mTimer.removeCallbacksAndMessages(this /* token */);
+        if (start && mMaxSubscriptionTime > 0) {
+            mTimer.postDelayed(this::onTimeout, this /* token */, mMaxSubscriptionTime);
+        }
+    }
+
+    private void onTimeout() {
+        Slog.e(TAG, "Max time exceeded for ALS logger - disabling: "
+                + mLightSensorListener.hashCode());
+        disable();
+    }
+}
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContext.java b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
index c86a8cb..8265203 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContext.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContext.java
@@ -46,6 +46,9 @@
     /** If the display is in AOD. */
     boolean isAod();
 
+    /** If the device is awake or is becoming awake. */
+    boolean isAwake();
+
     /**
      * Subscribe to context changes.
      *
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
index 9d2fde7..3d1a634 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricContextProvider.java
@@ -43,7 +43,7 @@
 /**
  * A default provider for {@link BiometricContext}.
  */
-class BiometricContextProvider implements BiometricContext {
+final class BiometricContextProvider implements BiometricContext {
 
     private static final String TAG = "BiometricContextProvider";
 
@@ -76,7 +76,8 @@
     private final Map<Integer, InstanceId> mSession = new ConcurrentHashMap<>();
 
     private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
-    private boolean mIsDozing = false;
+    private boolean mIsAod = false;
+    private boolean mIsAwake = false;
 
     @VisibleForTesting
     BiometricContextProvider(@NonNull AmbientDisplayConfiguration ambientDisplayConfiguration,
@@ -85,9 +86,14 @@
         try {
             service.setBiometicContextListener(new IBiometricContextListener.Stub() {
                 @Override
-                public void onDozeChanged(boolean isDozing) {
-                    mIsDozing = isDozing;
-                    notifyChanged();
+                public void onDozeChanged(boolean isDozing, boolean isAwake) {
+                    isDozing = isDozing && isAodEnabled();
+                    final boolean changed = (mIsAod != isDozing) || (mIsAwake != isAwake);
+                    if (changed) {
+                        mIsAod = isDozing;
+                        mIsAwake = isAwake;
+                        notifyChanged();
+                    }
                 }
 
                 private void notifyChanged() {
@@ -97,6 +103,10 @@
                         notifySubscribers();
                     }
                 }
+
+                private boolean isAodEnabled() {
+                    return mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
+                }
             });
             service.registerSessionListener(SESSION_TYPES, new ISessionListener.Stub() {
                 @Override
@@ -161,7 +171,12 @@
 
     @Override
     public boolean isAod() {
-        return mIsDozing && mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
+        return mIsAod;
+    }
+
+    @Override
+    public boolean isAwake() {
+        return mIsAwake;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
index 262be08..02b350e 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricLogger.java
@@ -17,21 +17,15 @@
 package com.android.server.biometrics.log;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
 import android.hardware.SensorManager;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.common.OperationContext;
 import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
-import android.util.Log;
 import android.util.Slog;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.server.biometrics.Utils;
@@ -43,61 +37,16 @@
 
     public static final String TAG = "BiometricLogger";
     public static final boolean DEBUG = false;
-    private static final Object sLock = new Object();
-
-    @GuardedBy("sLock")
-    private static int sAlsCounter;
 
     private final int mStatsModality;
     private final int mStatsAction;
     private final int mStatsClient;
     private final BiometricFrameworkStatsLogger mSink;
-    @NonNull private final SensorManager mSensorManager;
+    @NonNull private final ALSProbe mALSProbe;
 
     private long mFirstAcquireTimeMs;
-    private boolean mLightSensorEnabled = false;
     private boolean mShouldLogMetrics = true;
 
-    private class ALSProbe implements Probe {
-        private boolean mDestroyed = false;
-
-        @Override
-        public synchronized void enable() {
-            if (!mDestroyed) {
-                setLightSensorLoggingEnabled(getAmbientLightSensor(mSensorManager));
-            }
-        }
-
-        @Override
-        public synchronized void disable() {
-            if (!mDestroyed) {
-                setLightSensorLoggingEnabled(null);
-            }
-        }
-
-        @Override
-        public synchronized void destroy() {
-            disable();
-            mDestroyed = true;
-        }
-    }
-
-    // report only the most recent value
-    // consider com.android.server.display.utils.AmbientFilter or similar if need arises
-    private volatile float mLastAmbientLux = 0;
-
-    private final SensorEventListener mLightSensorListener = new SensorEventListener() {
-        @Override
-        public void onSensorChanged(SensorEvent event) {
-            mLastAmbientLux = event.values[0];
-        }
-
-        @Override
-        public void onAccuracyChanged(Sensor sensor, int accuracy) {
-            // Not used.
-        }
-    };
-
     /** Get a new logger with all unknown fields (for operations that do not require logs). */
     public static BiometricLogger ofUnknown(@NonNull Context context) {
         return new BiometricLogger(context, BiometricsProtoEnums.MODALITY_UNKNOWN,
@@ -105,6 +54,11 @@
     }
 
     /**
+     * Creates a new logger for an instance of a biometric operation.
+     *
+     * Do not reuse across operations. Instead, create a new one or use
+     * {@link #swapAction(Context, int)}.
+     *
      * @param context system_server context
      * @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
      * @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
@@ -125,7 +79,7 @@
         mStatsAction = statsAction;
         mStatsClient = statsClient;
         mSink = logSink;
-        mSensorManager = sensorManager;
+        mALSProbe = new ALSProbe(sensorManager);
     }
 
     /** Creates a new logger with the action replaced with the new action. */
@@ -136,6 +90,7 @@
     /** Disable logging metrics and only log critical events, such as system health issues. */
     public void disableMetrics() {
         mShouldLogMetrics = false;
+        mALSProbe.destroy();
     }
 
     /** {@link BiometricsProtoEnums} CLIENT_* constants */
@@ -265,7 +220,7 @@
                     + ", RequireConfirmation: " + requireConfirmation
                     + ", State: " + authState
                     + ", Latency: " + latency
-                    + ", Lux: " + mLastAmbientLux);
+                    + ", Lux: " + mALSProbe.getCurrentLux());
         } else {
             Slog.v(TAG, "Authentication latency: " + latency);
         }
@@ -276,7 +231,7 @@
 
         mSink.authenticate(operationContext, mStatsModality, mStatsAction, mStatsClient,
                 Utils.isDebugEnabled(context, targetUserId),
-                latency, authState, requireConfirmation, targetUserId, mLastAmbientLux);
+                latency, authState, requireConfirmation, targetUserId, mALSProbe.getCurrentLux());
     }
 
     /** Log enrollment outcome. */
@@ -290,7 +245,7 @@
                     + ", User: " + targetUserId
                     + ", Client: " + mStatsClient
                     + ", Latency: " + latency
-                    + ", Lux: " + mLastAmbientLux
+                    + ", Lux: " + mALSProbe.getCurrentLux()
                     + ", Success: " + enrollSuccessful);
         } else {
             Slog.v(TAG, "Enroll latency: " + latency);
@@ -301,7 +256,7 @@
         }
 
         mSink.enroll(mStatsModality, mStatsAction, mStatsClient,
-                targetUserId, latency, enrollSuccessful, mLastAmbientLux);
+                targetUserId, latency, enrollSuccessful, mALSProbe.getCurrentLux());
     }
 
     /** Report unexpected enrollment reported by the HAL. */
@@ -323,7 +278,9 @@
     }
 
     /**
-     * Get a callback to start/stop ALS capture when a client runs.
+     * Get a callback to start/stop ALS capture when the client runs. Do not create
+     * multiple callbacks since there is at most one light sensor (they will all share
+     * a single probe sampling from that sensor).
      *
      * If the probe should not run for the entire operation, do not set startWithClient and
      * start/stop the problem when needed.
@@ -331,53 +288,7 @@
      * @param startWithClient if probe should start automatically when the operation starts.
      */
     @NonNull
-    public CallbackWithProbe<Probe> createALSCallback(boolean startWithClient) {
-        return new CallbackWithProbe<>(new ALSProbe(), startWithClient);
-    }
-
-    /** The sensor to use for ALS logging. */
-    @Nullable
-    protected Sensor getAmbientLightSensor(@NonNull SensorManager sensorManager) {
-        return mShouldLogMetrics ? sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) : null;
-    }
-
-    private void setLightSensorLoggingEnabled(@Nullable Sensor lightSensor) {
-        if (DEBUG) {
-            Slog.v(TAG, "capturing ambient light using: "
-                    + (lightSensor != null ? lightSensor : "[disabled]"));
-        }
-
-        if (lightSensor != null) {
-            if (!mLightSensorEnabled) {
-                mLightSensorEnabled = true;
-                mLastAmbientLux = 0;
-                int localAlsCounter;
-                synchronized (sLock) {
-                    localAlsCounter = sAlsCounter++;
-                }
-
-                if (localAlsCounter == 0) {
-                    mSensorManager.registerListener(mLightSensorListener, lightSensor,
-                            SensorManager.SENSOR_DELAY_NORMAL);
-                } else {
-                    Slog.e(TAG, "Ignoring request to subscribe to ALSProbe due to non-zero ALS"
-                            + " counter: " + localAlsCounter);
-                    Slog.e(TAG, Log.getStackTraceString(new Throwable()));
-                }
-            }
-        } else {
-            mLightSensorEnabled = false;
-            mLastAmbientLux = 0;
-            mSensorManager.unregisterListener(mLightSensorListener);
-            int localAlsCounter;
-            synchronized (sLock) {
-                localAlsCounter = --sAlsCounter;
-            }
-            if (localAlsCounter != 0) {
-                Slog.e(TAG, "Non-zero ALS counter after unsubscribing from ALSProbe: "
-                        + localAlsCounter);
-                Slog.e(TAG, Log.getStackTraceString(new Throwable()));
-            }
-        }
+    public CallbackWithProbe<Probe> getAmbientLightProbe(boolean startWithClient) {
+        return new CallbackWithProbe<>(mALSProbe, startWithClient);
     }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 4eb6d38..8a24ff6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -29,7 +29,6 @@
 import android.hardware.biometrics.BiometricOverlayConstants;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.SystemClock;
 import android.security.KeyStore;
 import android.util.EventLog;
 import android.util.Slog;
@@ -46,9 +45,7 @@
  * A class to keep track of the authentication state for a given client.
  */
 public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
-        implements AuthenticationConsumer  {
-
-    private static final String TAG = "Biometrics/AuthenticationClient";
+        implements AuthenticationConsumer {
 
     // New, has not started yet
     public static final int STATE_NEW = 0;
@@ -67,28 +64,27 @@
             STATE_STARTED_PAUSED_ATTEMPTED,
             STATE_STOPPED})
     @interface State {}
-
+    private static final String TAG = "Biometrics/AuthenticationClient";
+    protected final long mOperationId;
     private final boolean mIsStrongBiometric;
     private final boolean mRequireConfirmation;
     private final ActivityTaskManager mActivityTaskManager;
     private final BiometricManager mBiometricManager;
-    @Nullable private final TaskStackListener mTaskStackListener;
+    @Nullable
+    private final TaskStackListener mTaskStackListener;
     private final LockoutTracker mLockoutTracker;
     private final boolean mIsRestricted;
     private final boolean mAllowBackgroundAuthentication;
     private final boolean mIsKeyguardBypassEnabled;
-
-    protected final long mOperationId;
-
+    // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
+    //  the state. We should think of a way to improve this in the future.
+    @State
+    protected int mState = STATE_NEW;
     private long mStartTimeMs;
 
     private boolean mAuthAttempted;
     private boolean mAuthSuccess = false;
 
-    // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
-    //  the state. We should think of a way to improve this in the future.
-    protected @State int mState = STATE_NEW;
-
     public AuthenticationClient(@NonNull Context context, @NonNull Supplier<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
             int targetUserId, long operationId, boolean restricted, @NonNull String owner,
@@ -111,8 +107,9 @@
         mIsKeyguardBypassEnabled = isKeyguardBypassEnabled;
     }
 
-    public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
-        final @LockoutTracker.LockoutMode int lockoutMode =
+    @LockoutTracker.LockoutMode
+    public int handleFailedAttempt(int userId) {
+        @LockoutTracker.LockoutMode final int lockoutMode =
                 mLockoutTracker.getLockoutModeForUser(userId);
         final PerformanceTracker performanceTracker =
                 PerformanceTracker.getInstanceForSensorId(getSensorId());
@@ -173,14 +170,16 @@
 
         final ClientMonitorCallbackConverter listener = getListener();
 
-        if (DEBUG) Slog.v(TAG, "onAuthenticated(" + authenticated + ")"
-                + ", ID:" + identifier.getBiometricId()
-                + ", Owner: " + getOwnerString()
-                + ", isBP: " + isBiometricPrompt()
-                + ", listener: " + listener
-                + ", requireConfirmation: " + mRequireConfirmation
-                + ", user: " + getTargetUserId()
-                + ", clientMonitor: " + toString());
+        if (DEBUG) {
+            Slog.v(TAG, "onAuthenticated(" + authenticated + ")"
+                    + ", ID:" + identifier.getBiometricId()
+                    + ", Owner: " + getOwnerString()
+                    + ", isBP: " + isBiometricPrompt()
+                    + ", listener: " + listener
+                    + ", requireConfirmation: " + mRequireConfirmation
+                    + ", user: " + getTargetUserId()
+                    + ", clientMonitor: " + this);
+        }
 
         final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
         if (isCryptoOperation()) {
@@ -239,142 +238,57 @@
                         getSensorId(), getTargetUserId(), byteToken);
             }
 
-            final CoexCoordinator coordinator = CoexCoordinator.getInstance();
-            coordinator.onAuthenticationSucceeded(SystemClock.uptimeMillis(), this,
-                    new CoexCoordinator.Callback() {
-                @Override
-                public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
-                    if (addAuthTokenIfStrong && mIsStrongBiometric) {
-                        final int result = KeyStore.getInstance().addAuthToken(byteToken);
-                        Slog.d(TAG, "addAuthToken: " + result);
+            // For BP, BiometricService will add the authToken to Keystore.
+            if (!isBiometricPrompt() && mIsStrongBiometric) {
+                final int result = KeyStore.getInstance().addAuthToken(byteToken);
+                if (result != KeyStore.NO_ERROR) {
+                    Slog.d(TAG, "Error adding auth token : " + result);
+                } else {
+                    Slog.d(TAG, "addAuthToken: " + result);
+                }
+            } else {
+                Slog.d(TAG, "Skipping addAuthToken");
+            }
+            try {
+                if (listener != null) {
+                    if (!mIsRestricted) {
+                        listener.onAuthenticationSucceeded(getSensorId(), identifier, byteToken,
+                                getTargetUserId(), mIsStrongBiometric);
                     } else {
-                        Slog.d(TAG, "Skipping addAuthToken");
+                        listener.onAuthenticationSucceeded(getSensorId(), null /* identifier */,
+                                byteToken,
+                                getTargetUserId(), mIsStrongBiometric);
                     }
-
-                    if (listener != null) {
-                        try {
-                            // Explicitly have if/else here to make it super obvious in case the
-                            // code is touched in the future.
-                            if (!mIsRestricted) {
-                                listener.onAuthenticationSucceeded(getSensorId(),
-                                        identifier,
-                                        byteToken,
-                                        getTargetUserId(),
-                                        mIsStrongBiometric);
-                            } else {
-                                listener.onAuthenticationSucceeded(getSensorId(),
-                                        null /* identifier */,
-                                        byteToken,
-                                        getTargetUserId(),
-                                        mIsStrongBiometric);
-                            }
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "Unable to notify listener", e);
-                        }
-                    } else {
-                        Slog.w(TAG, "Client not listening");
-                    }
+                } else {
+                    Slog.e(TAG, "Received successful auth, but client was not listening");
                 }
-
-                @Override
-                public void sendHapticFeedback() {
-                    if (listener != null && mShouldVibrate) {
-                        vibrateSuccess();
-                    }
-                }
-
-                @Override
-                public void handleLifecycleAfterAuth() {
-                    AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
-                }
-
-                @Override
-                public void sendAuthenticationCanceled() {
-                    sendCancelOnly(listener);
-                }
-            });
-        } else { // not authenticated
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to notify listener", e);
+                mCallback.onClientFinished(this, false);
+                return;
+            }
+        } else {
             if (isBackgroundAuth) {
                 Slog.e(TAG, "cancelling due to background auth");
                 cancel();
             } else {
                 // Allow system-defined limit of number of attempts before giving up
-                final @LockoutTracker.LockoutMode int lockoutMode =
+                @LockoutTracker.LockoutMode final int lockoutMode =
                         handleFailedAttempt(getTargetUserId());
                 if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
                     markAlreadyDone();
                 }
 
-                final CoexCoordinator coordinator = CoexCoordinator.getInstance();
-                coordinator.onAuthenticationRejected(SystemClock.uptimeMillis(), this, lockoutMode,
-                        new CoexCoordinator.Callback() {
-                            @Override
-                            public void sendAuthenticationResult(boolean addAuthTokenIfStrong) {
-                                if (listener != null) {
-                                    try {
-                                        listener.onAuthenticationFailed(getSensorId());
-                                    } catch (RemoteException e) {
-                                        Slog.e(TAG, "Unable to notify listener", e);
-                                    }
-                                }
-                            }
-
-                            @Override
-                            public void sendHapticFeedback() {
-                                if (listener != null && mShouldVibrate) {
-                                    vibrateError();
-                                }
-                            }
-
-                            @Override
-                            public void handleLifecycleAfterAuth() {
-                                AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
-                            }
-
-                            @Override
-                            public void sendAuthenticationCanceled() {
-                                sendCancelOnly(listener);
-                            }
-                        });
+                try {
+                    listener.onAuthenticationFailed(getSensorId());
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to notify listener", e);
+                    mCallback.onClientFinished(this, false);
+                    return;
+                }
             }
         }
-    }
-
-    /**
-     * Only call this method on interfaces where lockout does not come from onError, I.E. the
-     * old HIDL implementation.
-     */
-    protected void onLockoutTimed(long durationMillis) {
-        final ClientMonitorCallbackConverter listener = getListener();
-        final CoexCoordinator coordinator = CoexCoordinator.getInstance();
-        coordinator.onAuthenticationError(this, BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
-                new CoexCoordinator.ErrorCallback() {
-            @Override
-            public void sendHapticFeedback() {
-                if (listener != null && mShouldVibrate) {
-                    vibrateError();
-                }
-            }
-        });
-    }
-
-    /**
-     * Only call this method on interfaces where lockout does not come from onError, I.E. the
-     * old HIDL implementation.
-     */
-    protected void onLockoutPermanent() {
-        final ClientMonitorCallbackConverter listener = getListener();
-        final CoexCoordinator coordinator = CoexCoordinator.getInstance();
-        coordinator.onAuthenticationError(this,
-                BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
-                new CoexCoordinator.ErrorCallback() {
-            @Override
-            public void sendHapticFeedback() {
-                if (listener != null && mShouldVibrate) {
-                    vibrateError();
-                }
-            }
-        });
+        AuthenticationClient.this.handleLifecycleAfterAuth(authenticated);
     }
 
     private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) {
@@ -396,7 +310,7 @@
     public void onAcquired(int acquiredInfo, int vendorCode) {
         super.onAcquired(acquiredInfo, vendorCode);
 
-        final @LockoutTracker.LockoutMode int lockoutMode =
+        @LockoutTracker.LockoutMode final int lockoutMode =
                 mLockoutTracker.getLockoutModeForUser(getTargetUserId());
         if (lockoutMode == LockoutTracker.LOCKOUT_NONE) {
             PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId());
@@ -408,8 +322,6 @@
     public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) {
         super.onError(errorCode, vendorCode);
         mState = STATE_STOPPED;
-
-        CoexCoordinator.getInstance().onAuthenticationError(this, errorCode, this::vibrateError);
     }
 
     /**
@@ -419,7 +331,7 @@
     public void start(@NonNull ClientMonitorCallback callback) {
         super.start(callback);
 
-        final @LockoutTracker.LockoutMode int lockoutMode =
+        @LockoutTracker.LockoutMode final int lockoutMode =
                 mLockoutTracker.getLockoutModeForUser(getTargetUserId());
         if (lockoutMode != LockoutTracker.LOCKOUT_NONE) {
             Slog.v(TAG, "In lockout mode(" + lockoutMode + ") ; disallowing authentication");
@@ -450,22 +362,20 @@
     }
 
     /**
-     * Handles lifecycle, e.g. {@link BiometricScheduler},
-     * {@link com.android.server.biometrics.sensors.BaseClientMonitor.Callback} after authentication
-     * results are known. Note that this happens asynchronously from (but shortly after)
-     * {@link #onAuthenticated(BiometricAuthenticator.Identifier, boolean, ArrayList)} and allows
-     * {@link CoexCoordinator} a chance to invoke/delay this event.
-     * @param authenticated
+     * Handles lifecycle, e.g. {@link BiometricScheduler} after authentication. This is necessary
+     * as different clients handle the lifecycle of authentication success/reject differently. I.E.
+     * Fingerprint does not finish authentication when it is rejected.
      */
     protected abstract void handleLifecycleAfterAuth(boolean authenticated);
 
     /**
      * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched.
-     *         etc)
+     * etc)
      */
     public abstract boolean wasUserDetected();
 
-    public @State int getState() {
+    @State
+    public int getState() {
         return mState;
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index 63609f7..9317c4e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -54,7 +54,7 @@
  * interactions with the HAL before finishing.
  *
  * We currently assume (and require) that each biometric sensor have its own instance of a
- * {@link BiometricScheduler}. See {@link CoexCoordinator}.
+ * {@link BiometricScheduler}.
  */
 @MainThread
 public class BiometricScheduler {
@@ -156,7 +156,6 @@
     private int mTotalOperationsHandled;
     private final int mRecentOperationsLimit;
     @NonNull private final List<Integer> mRecentOperations;
-    @NonNull private final CoexCoordinator mCoexCoordinator;
 
     // Internal callback, notified when an operation is complete. Notifies the requester
     // that the operation is complete, before performing internal scheduler work (such as
@@ -165,11 +164,6 @@
         @Override
         public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
             Slog.d(getTag(), "[Started] " + clientMonitor);
-
-            if (clientMonitor instanceof AuthenticationClient) {
-                mCoexCoordinator.addAuthenticationClient(mSensorType,
-                        (AuthenticationClient<?>) clientMonitor);
-            }
         }
 
         @Override
@@ -189,10 +183,6 @@
                 }
 
                 Slog.d(getTag(), "[Finishing] " + clientMonitor + ", success: " + success);
-                if (clientMonitor instanceof AuthenticationClient) {
-                    mCoexCoordinator.removeAuthenticationClient(mSensorType,
-                            (AuthenticationClient<?>) clientMonitor);
-                }
 
                 if (mGestureAvailabilityDispatcher != null) {
                     mGestureAvailabilityDispatcher.markSensorActive(
@@ -216,8 +206,7 @@
             @SensorType int sensorType,
             @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
             @NonNull IBiometricService biometricService,
-            int recentOperationsLimit,
-            @NonNull CoexCoordinator coexCoordinator) {
+            int recentOperationsLimit) {
         mBiometricTag = tag;
         mHandler = handler;
         mSensorType = sensorType;
@@ -227,7 +216,6 @@
         mCrashStates = new ArrayDeque<>();
         mRecentOperationsLimit = recentOperationsLimit;
         mRecentOperations = new ArrayList<>();
-        mCoexCoordinator = coexCoordinator;
     }
 
     /**
@@ -244,7 +232,7 @@
         this(tag, new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher,
                 IBiometricService.Stub.asInterface(
                         ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
-                LOG_NUM_RECENT_OPERATIONS, CoexCoordinator.getInstance());
+                LOG_NUM_RECENT_OPERATIONS);
     }
 
     @VisibleForTesting
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/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
deleted file mode 100644
index c8a90e7..0000000
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ /dev/null
@@ -1,525 +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.server.biometrics.sensors;
-
-import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE;
-import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS;
-import static com.android.server.biometrics.sensors.BiometricScheduler.sensorTypeToString;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.hardware.biometrics.BiometricConstants;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.biometrics.sensors.BiometricScheduler.SensorType;
-import com.android.server.biometrics.sensors.fingerprint.Udfps;
-
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Map;
-
-/**
- * Singleton that contains the core logic for determining if haptics and authentication callbacks
- * should be sent to receivers. Note that this class is used even when coex is not required (e.g.
- * single sensor devices, or multi-sensor devices where only a single sensor is authenticating).
- * This allows us to have all business logic in one testable place.
- */
-public class CoexCoordinator {
-
-    private static final String TAG = "BiometricCoexCoordinator";
-    public static final String SETTING_ENABLE_NAME =
-            "com.android.server.biometrics.sensors.CoexCoordinator.enable";
-    public static final String FACE_HAPTIC_DISABLE =
-            "com.android.server.biometrics.sensors.CoexCoordinator.disable_face_haptics";
-    private static final boolean DEBUG = true;
-
-    // Successful authentications should be used within this amount of time.
-    static final long SUCCESSFUL_AUTH_VALID_DURATION_MS = 5000;
-
-    /**
-     * Callback interface notifying the owner of "results" from the CoexCoordinator's business
-     * logic for accept and reject.
-     */
-    interface Callback {
-        /**
-         * Requests the owner to send the result (success/reject) and any associated info to the
-         * receiver (e.g. keyguard, BiometricService, etc).
-         */
-        void sendAuthenticationResult(boolean addAuthTokenIfStrong);
-
-        /**
-         * Requests the owner to initiate a vibration for this event.
-         */
-        void sendHapticFeedback();
-
-        /**
-         * Requests the owner to handle the AuthenticationClient's lifecycle (e.g. finish and remove
-         * from scheduler if auth was successful).
-         */
-        void handleLifecycleAfterAuth();
-
-        /**
-         * Requests the owner to notify the caller that authentication was canceled.
-         */
-        void sendAuthenticationCanceled();
-    }
-
-    /**
-     * Callback interface notifying the owner of "results" from the CoexCoordinator's business
-     * logic for errors.
-     */
-    interface ErrorCallback {
-        /**
-         * Requests the owner to initiate a vibration for this event.
-         */
-        void sendHapticFeedback();
-    }
-
-    private static final CoexCoordinator sInstance = new CoexCoordinator();
-
-    @VisibleForTesting
-    public static class SuccessfulAuth {
-        final long mAuthTimestamp;
-        final @SensorType int mSensorType;
-        final AuthenticationClient<?> mAuthenticationClient;
-        final Callback mCallback;
-        final CleanupRunnable mCleanupRunnable;
-
-        public static class CleanupRunnable implements Runnable {
-            @NonNull final LinkedList<SuccessfulAuth> mSuccessfulAuths;
-            @NonNull final SuccessfulAuth mAuth;
-            @NonNull final Callback mCallback;
-
-            public CleanupRunnable(@NonNull LinkedList<SuccessfulAuth> successfulAuths,
-                    @NonNull SuccessfulAuth auth, @NonNull Callback callback) {
-                mSuccessfulAuths = successfulAuths;
-                mAuth = auth;
-                mCallback = callback;
-            }
-
-            @Override
-            public void run() {
-                final boolean removed = mSuccessfulAuths.remove(mAuth);
-                Slog.w(TAG, "Removing stale successfulAuth: " + mAuth.toString()
-                        + ", success: " + removed);
-                mCallback.handleLifecycleAfterAuth();
-            }
-        }
-
-        public SuccessfulAuth(@NonNull Handler handler,
-                @NonNull LinkedList<SuccessfulAuth> successfulAuths,
-                long currentTimeMillis,
-                @SensorType int sensorType,
-                @NonNull AuthenticationClient<?> authenticationClient,
-                @NonNull Callback callback) {
-            mAuthTimestamp = currentTimeMillis;
-            mSensorType = sensorType;
-            mAuthenticationClient = authenticationClient;
-            mCallback = callback;
-
-            mCleanupRunnable = new CleanupRunnable(successfulAuths, this, callback);
-
-            handler.postDelayed(mCleanupRunnable, SUCCESSFUL_AUTH_VALID_DURATION_MS);
-        }
-
-        @Override
-        public String toString() {
-            return "SensorType: " + sensorTypeToString(mSensorType)
-                    + ", mAuthTimestamp: " + mAuthTimestamp
-                    + ", authenticationClient: " + mAuthenticationClient;
-        }
-    }
-
-    /** The singleton instance. */
-    @NonNull
-    public static CoexCoordinator getInstance() {
-        return sInstance;
-    }
-
-    @VisibleForTesting
-    public void setAdvancedLogicEnabled(boolean enabled) {
-        mAdvancedLogicEnabled = enabled;
-    }
-
-    public void setFaceHapticDisabledWhenNonBypass(boolean disabled) {
-        mFaceHapticDisabledWhenNonBypass = disabled;
-    }
-
-    @VisibleForTesting
-    void reset() {
-        mClientMap.clear();
-    }
-
-    // SensorType to AuthenticationClient map
-    private final Map<Integer, AuthenticationClient<?>> mClientMap = new HashMap<>();
-    @VisibleForTesting final LinkedList<SuccessfulAuth> mSuccessfulAuths = new LinkedList<>();
-    private boolean mAdvancedLogicEnabled;
-    private boolean mFaceHapticDisabledWhenNonBypass;
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
-    private CoexCoordinator() {}
-
-    public void addAuthenticationClient(@BiometricScheduler.SensorType int sensorType,
-            @NonNull AuthenticationClient<?> client) {
-        if (DEBUG) {
-            Slog.d(TAG, "addAuthenticationClient(" + sensorTypeToString(sensorType) + ")"
-                    + ", client: " + client);
-        }
-
-        if (mClientMap.containsKey(sensorType)) {
-            Slog.w(TAG, "Overwriting existing client: " + mClientMap.get(sensorType)
-                    + " with new client: " + client);
-        }
-
-        mClientMap.put(sensorType, client);
-    }
-
-    public void removeAuthenticationClient(@BiometricScheduler.SensorType int sensorType,
-            @NonNull AuthenticationClient<?> client) {
-        if (DEBUG) {
-            Slog.d(TAG, "removeAuthenticationClient(" + sensorTypeToString(sensorType) + ")"
-                    + ", client: " + client);
-        }
-
-        if (!mClientMap.containsKey(sensorType)) {
-            Slog.e(TAG, "sensorType: " + sensorType + " does not exist in map. Client: " + client);
-            return;
-        }
-        mClientMap.remove(sensorType);
-    }
-
-    /**
-     * Notify the coordinator that authentication succeeded (accepted)
-     */
-    public void onAuthenticationSucceeded(long currentTimeMillis,
-            @NonNull AuthenticationClient<?> client,
-            @NonNull Callback callback) {
-        final boolean isUsingSingleModality = isSingleAuthOnly(client);
-
-        if (client.isBiometricPrompt()) {
-            if (!isUsingSingleModality && hasMultipleSuccessfulAuthentications()) {
-                // only send feedback on the first one
-            } else {
-                callback.sendHapticFeedback();
-            }
-            // For BP, BiometricService will add the authToken to Keystore.
-            callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */);
-            callback.handleLifecycleAfterAuth();
-        } else if (isUnknownClient(client)) {
-            // Client doesn't exist in our map for some reason. Give the user feedback so the
-            // device doesn't feel like it's stuck. All other cases below can assume that the
-            // client exists in our map.
-            callback.sendHapticFeedback();
-            callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-            callback.handleLifecycleAfterAuth();
-        } else if (mAdvancedLogicEnabled && client.isKeyguard()) {
-            if (isUsingSingleModality) {
-                // Single sensor authentication
-                callback.sendHapticFeedback();
-                callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-                callback.handleLifecycleAfterAuth();
-            } else {
-                // Multi sensor authentication
-                AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
-                AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
-                if (isCurrentFaceAuth(client)) {
-                    if (isUdfpsActivelyAuthing(udfps)) {
-                        // Face auth success while UDFPS is actively authing. No callback, no haptic
-                        // Feedback will be provided after UDFPS result:
-                        // 1) UDFPS succeeds - simply remove this from the queue
-                        // 2) UDFPS rejected - use this face auth success to notify clients
-                        mSuccessfulAuths.add(new SuccessfulAuth(mHandler, mSuccessfulAuths,
-                                currentTimeMillis, SENSOR_TYPE_FACE, client, callback));
-                    } else {
-                        if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
-                            Slog.w(TAG, "Skipping face success haptic");
-                        } else {
-                            callback.sendHapticFeedback();
-                        }
-                        callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-                        callback.handleLifecycleAfterAuth();
-                    }
-                } else if (isCurrentUdfps(client)) {
-                    if (isFaceScanning()) {
-                        // UDFPS succeeds while face is still scanning
-                        // Cancel face auth and/or prevent it from invoking haptics/callbacks after
-                        face.cancel();
-                    }
-
-                    removeAndFinishAllFaceFromQueue();
-
-                    callback.sendHapticFeedback();
-                    callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-                    callback.handleLifecycleAfterAuth();
-                } else {
-                    // Capacitive fingerprint sensor (or other)
-                    callback.sendHapticFeedback();
-                    callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-                    callback.handleLifecycleAfterAuth();
-                }
-            }
-        } else {
-            // Non-keyguard authentication. For example, Fingerprint Settings use of
-            // FingerprintManager for highlighting fingers
-            callback.sendHapticFeedback();
-            callback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-            callback.handleLifecycleAfterAuth();
-        }
-    }
-
-    /**
-     * Notify the coordinator that a rejection has occurred.
-     */
-    public void onAuthenticationRejected(long currentTimeMillis,
-            @NonNull AuthenticationClient<?> client,
-            @LockoutTracker.LockoutMode int lockoutMode,
-            @NonNull Callback callback) {
-        final boolean isUsingSingleModality = isSingleAuthOnly(client);
-
-        if (mAdvancedLogicEnabled && client.isKeyguard()) {
-            if (isUsingSingleModality) {
-                callback.sendHapticFeedback();
-                callback.handleLifecycleAfterAuth();
-            } else {
-                // Multi sensor authentication
-                AuthenticationClient<?> udfps = mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
-                AuthenticationClient<?> face = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
-                if (isCurrentFaceAuth(client)) {
-                    if (isUdfpsActivelyAuthing(udfps)) {
-                        // UDFPS should still be running in this case, do not vibrate. However, we
-                        // should notify the callback and finish the client, so that Keyguard and
-                        // BiometricScheduler do not get stuck.
-                        Slog.d(TAG, "Face rejected in multi-sensor auth, udfps: " + udfps);
-                        callback.handleLifecycleAfterAuth();
-                    } else if (isUdfpsAuthAttempted(udfps)) {
-                        // If UDFPS is STATE_STARTED_PAUSED (e.g. finger rejected but can still
-                        // auth after pointer goes down, it means UDFPS encountered a rejection. In
-                        // this case, we need to play the final reject haptic since face auth is
-                        // also done now.
-                        callback.sendHapticFeedback();
-                        callback.handleLifecycleAfterAuth();
-                    } else {
-                        // UDFPS auth has never been attempted.
-                        if (mFaceHapticDisabledWhenNonBypass && !face.isKeyguardBypassEnabled()) {
-                            Slog.w(TAG, "Skipping face reject haptic");
-                        } else {
-                            callback.sendHapticFeedback();
-                        }
-                        callback.handleLifecycleAfterAuth();
-                    }
-                } else if (isCurrentUdfps(client)) {
-                    // Face should either be running, or have already finished
-                    SuccessfulAuth auth = popSuccessfulFaceAuthIfExists(currentTimeMillis);
-                    if (auth != null) {
-                        Slog.d(TAG, "Using recent auth: " + auth);
-                        callback.handleLifecycleAfterAuth();
-
-                        auth.mCallback.sendHapticFeedback();
-                        auth.mCallback.sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-                        auth.mCallback.handleLifecycleAfterAuth();
-                    } else {
-                        Slog.d(TAG, "UDFPS rejected in multi-sensor auth");
-                        callback.sendHapticFeedback();
-                        callback.handleLifecycleAfterAuth();
-                    }
-                } else {
-                    Slog.d(TAG, "Unknown client rejected: " + client);
-                    callback.sendHapticFeedback();
-                    callback.handleLifecycleAfterAuth();
-                }
-            }
-        } else if (client.isBiometricPrompt() && !isUsingSingleModality) {
-            if (!isCurrentFaceAuth(client)) {
-                callback.sendHapticFeedback();
-            }
-            callback.handleLifecycleAfterAuth();
-        } else {
-            callback.sendHapticFeedback();
-            callback.handleLifecycleAfterAuth();
-        }
-
-        // Always notify keyguard, otherwise the cached "running" state in KeyguardUpdateMonitor
-        // will get stuck.
-        if (lockoutMode == LockoutTracker.LOCKOUT_NONE) {
-            // Don't send onAuthenticationFailed if we're in lockout, it causes a
-            // janky UI on Keyguard/BiometricPrompt since "authentication failed"
-            // will show briefly and be replaced by "device locked out" message.
-            callback.sendAuthenticationResult(false /* addAuthTokenIfStrong */);
-        }
-    }
-
-    /**
-     * Notify the coordinator that an error has occurred.
-     */
-    public void onAuthenticationError(@NonNull AuthenticationClient<?> client,
-            @BiometricConstants.Errors int error, @NonNull ErrorCallback callback) {
-        final boolean isUsingSingleModality = isSingleAuthOnly(client);
-
-        // Figure out non-coex state
-        final boolean shouldUsuallyVibrate;
-        if (isCurrentFaceAuth(client)) {
-            final boolean notDetectedOnKeyguard = client.isKeyguard() && !client.wasUserDetected();
-            final boolean authAttempted = client.wasAuthAttempted();
-
-            switch (error) {
-                case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
-                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
-                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
-                    shouldUsuallyVibrate = authAttempted && !notDetectedOnKeyguard;
-                    break;
-                default:
-                    shouldUsuallyVibrate = false;
-                    break;
-            }
-        } else {
-            shouldUsuallyVibrate = false;
-        }
-
-        // Figure out coex state
-        final boolean hapticSuppressedByCoex;
-        if (mAdvancedLogicEnabled && client.isKeyguard()) {
-            if (isUsingSingleModality) {
-                hapticSuppressedByCoex = false;
-            } else {
-                hapticSuppressedByCoex = isCurrentFaceAuth(client)
-                        && !client.isKeyguardBypassEnabled();
-            }
-        } else if (client.isBiometricPrompt() && !isUsingSingleModality) {
-            hapticSuppressedByCoex = isCurrentFaceAuth(client);
-        } else {
-            hapticSuppressedByCoex = false;
-        }
-
-        // Combine and send feedback if appropriate
-        if (shouldUsuallyVibrate && !hapticSuppressedByCoex) {
-            callback.sendHapticFeedback();
-        } else {
-            Slog.v(TAG, "no haptic shouldUsuallyVibrate: " + shouldUsuallyVibrate
-                    + ", hapticSuppressedByCoex: " + hapticSuppressedByCoex);
-        }
-    }
-
-    @Nullable
-    private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
-        for (SuccessfulAuth auth : mSuccessfulAuths) {
-            if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
-                // TODO(b/193089985): This removes the auth but does not notify the client with
-                //  an appropriate lifecycle event (such as ERROR_CANCELED), and violates the
-                //  API contract. However, this might be OK for now since the validity duration
-                //  is way longer than the time it takes to auth with fingerprint.
-                Slog.e(TAG, "Removing stale auth: " + auth);
-                mSuccessfulAuths.remove(auth);
-            } else if (auth.mSensorType == SENSOR_TYPE_FACE) {
-                mSuccessfulAuths.remove(auth);
-                return auth;
-            }
-        }
-        return null;
-    }
-
-    private void removeAndFinishAllFaceFromQueue() {
-        // Note that these auth are all successful, but have never notified the client (e.g.
-        // keyguard). To comply with the authentication lifecycle, we must notify the client that
-        // auth is "done". The safest thing to do is to send ERROR_CANCELED.
-        for (SuccessfulAuth auth : mSuccessfulAuths) {
-            if (auth.mSensorType == SENSOR_TYPE_FACE) {
-                Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth);
-                auth.mCallback.sendAuthenticationCanceled();
-                auth.mCallback.handleLifecycleAfterAuth();
-                mSuccessfulAuths.remove(auth);
-            }
-        }
-    }
-
-    private boolean isCurrentFaceAuth(@NonNull AuthenticationClient<?> client) {
-        return client == mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
-    }
-
-    private boolean isCurrentUdfps(@NonNull AuthenticationClient<?> client) {
-        return client == mClientMap.getOrDefault(SENSOR_TYPE_UDFPS, null);
-    }
-
-    private boolean isFaceScanning() {
-        AuthenticationClient<?> client = mClientMap.getOrDefault(SENSOR_TYPE_FACE, null);
-        return client != null && client.getState() == AuthenticationClient.STATE_STARTED;
-    }
-
-    private static boolean isUdfpsActivelyAuthing(@Nullable AuthenticationClient<?> client) {
-        if (client instanceof Udfps) {
-            return client.getState() == AuthenticationClient.STATE_STARTED;
-        }
-        return false;
-    }
-
-    private static boolean isUdfpsAuthAttempted(@Nullable AuthenticationClient<?> client) {
-        if (client instanceof Udfps) {
-            return client.getState() == AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED;
-        }
-        return false;
-    }
-
-    private boolean isUnknownClient(@NonNull AuthenticationClient<?> client) {
-        for (AuthenticationClient<?> c : mClientMap.values()) {
-            if (c == client) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean isSingleAuthOnly(@NonNull AuthenticationClient<?> client) {
-        if (mClientMap.values().size() != 1) {
-            return false;
-        }
-
-        for (AuthenticationClient<?> c : mClientMap.values()) {
-            if (c != client) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    private boolean hasMultipleSuccessfulAuthentications() {
-        int count = 0;
-        for (AuthenticationClient<?> c : mClientMap.values()) {
-            if (c.wasAuthSuccessful()) {
-                count++;
-            }
-            if (count > 1) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Enabled: ").append(mAdvancedLogicEnabled);
-        sb.append(", Face Haptic Disabled: ").append(mFaceHapticDisabledWhenNonBypass);
-        sb.append(", Queue size: " ).append(mSuccessfulAuths.size());
-        for (SuccessfulAuth auth : mSuccessfulAuths) {
-            sb.append(", Auth: ").append(auth.toString());
-        }
-
-        return sb.toString();
-    }
-}
diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
index ae75b7d..a486d16 100644
--- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java
@@ -95,10 +95,9 @@
             @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher,
             @NonNull IBiometricService biometricService,
             @NonNull CurrentUserRetriever currentUserRetriever,
-            @NonNull UserSwitchCallback userSwitchCallback,
-            @NonNull CoexCoordinator coexCoordinator) {
+            @NonNull UserSwitchCallback userSwitchCallback) {
         super(tag, handler, sensorType, gestureAvailabilityDispatcher, biometricService,
-                LOG_NUM_RECENT_OPERATIONS, coexCoordinator);
+                LOG_NUM_RECENT_OPERATIONS);
 
         mCurrentUserRetriever = currentUserRetriever;
         mUserSwitchCallback = userSwitchCallback;
@@ -112,7 +111,7 @@
         this(tag, new Handler(Looper.getMainLooper()), sensorType, gestureAvailabilityDispatcher,
                 IBiometricService.Stub.asInterface(
                         ServiceManager.getService(Context.BIOMETRIC_SERVICE)),
-                currentUserRetriever, userSwitchCallback, CoexCoordinator.getInstance());
+                currentUserRetriever, userSwitchCallback);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index d0c58fd..2e4c323 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -100,9 +100,7 @@
                 owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
                 isStrongBiometric, null /* taskStackListener */, lockoutCache,
                 allowBackgroundAuthentication,
-                context.getResources().getBoolean(
-                        com.android.internal.R.bool.system_server_plays_face_haptics)
-                /* shouldVibrate */,
+                false /* shouldVibrate */,
                 isKeyguardBypassEnabled);
         setRequestId(requestId);
         mUsageStats = usageStats;
@@ -131,7 +129,7 @@
     @Override
     protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
         return new ClientMonitorCompositeCallback(
-                getLogger().createALSCallback(true /* startWithClient */), callback);
+                getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
     }
 
     @Override
@@ -274,7 +272,6 @@
 
     @Override
     public void onLockoutTimed(long durationMillis) {
-        super.onLockoutTimed(durationMillis);
         mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
         // Lockout metrics are logged as an error code.
         final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT;
@@ -290,7 +287,6 @@
 
     @Override
     public void onLockoutPermanent() {
-        super.onLockoutPermanent();
         mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
         // Lockout metrics are logged as an error code.
         final int error = BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
index da78536..5d62cde 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceEnrollClient.java
@@ -115,7 +115,7 @@
     @Override
     protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
         return new ClientMonitorCompositeCallback(mPreviewHandleDeleterCallback,
-                getLogger().createALSCallback(true /* startWithClient */), callback);
+                getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 1935a5b..91eec7d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -74,7 +74,7 @@
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
                 isStrongBiometric, null /* taskStackListener */,
-                lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
+                lockoutTracker, allowBackgroundAuthentication, false /* shouldVibrate */,
                 isKeyguardBypassEnabled);
         setRequestId(requestId);
         mUsageStats = usageStats;
@@ -101,7 +101,7 @@
     @Override
     protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
         return new ClientMonitorCompositeCallback(
-                getLogger().createALSCallback(true /* startWithClient */), callback);
+                getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
index 226e458..16d2f7a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceEnrollClient.java
@@ -75,7 +75,7 @@
     @Override
     protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
         return new ClientMonitorCompositeCallback(
-                getLogger().createALSCallback(true /* startWithClient */), callback);
+                getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index b530c8d..e0955b7 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -131,13 +131,13 @@
                 taskStackListener,
                 lockoutCache,
                 allowBackgroundAuthentication,
-                true /* shouldVibrate */,
+                false /* shouldVibrate */,
                 false /* isKeyguardBypassEnabled */);
         setRequestId(requestId);
         mLockoutCache = lockoutCache;
         mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
         mSensorProps = sensorProps;
-        mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
+        mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
         mHandler = handler;
 
         mWaitForAuthKeyguard =
@@ -315,21 +315,27 @@
     private ICancellationSignal doAuthenticate() throws RemoteException {
         final AidlSession session = getFreshDaemon();
 
+        final OperationContext opContext = getOperationContext();
+        getBiometricContext().subscribe(opContext, ctx -> {
+            if (session.hasContextMethods()) {
+                try {
+                    session.getSession().onContextChanged(ctx);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to notify context changed", e);
+                }
+            }
+
+            // TODO(b/243836005): this should come via ctx
+            final boolean isAwake = getBiometricContext().isAwake();
+            if (isAwake) {
+                mALSProbeCallback.getProbe().enable();
+            } else {
+                mALSProbeCallback.getProbe().disable();
+            }
+        });
+
         if (session.hasContextMethods()) {
-            final OperationContext opContext = getOperationContext();
-            final ICancellationSignal cancel =
-                    session.getSession().authenticateWithContext(mOperationId, opContext);
-            getBiometricContext()
-                    .subscribe(
-                            opContext,
-                            ctx -> {
-                                try {
-                                    session.getSession().onContextChanged(ctx);
-                                } catch (RemoteException e) {
-                                    Slog.e(TAG, "Unable to notify context changed", e);
-                                }
-                            });
-            return cancel;
+            return session.getSession().authenticateWithContext(mOperationId, opContext);
         } else {
             return session.getSession().authenticate(mOperationId);
         }
@@ -360,7 +366,6 @@
         try {
             mIsPointerDown = true;
             mState = STATE_STARTED;
-            mALSProbeCallback.getProbe().enable();
 
             final AidlSession session = getFreshDaemon();
             if (session.hasContextMethods()) {
@@ -389,7 +394,6 @@
         try {
             mIsPointerDown = false;
             mState = STATE_STARTED_PAUSED_ATTEMPTED;
-            mALSProbeCallback.getProbe().disable();
 
             final AidlSession session = getFreshDaemon();
             if (session.hasContextMethods()) {
@@ -424,7 +428,6 @@
 
     @Override
     public void onLockoutTimed(long durationMillis) {
-        super.onLockoutTimed(durationMillis);
         mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_TIMED);
         // Lockout metrics are logged as an error code.
         final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT;
@@ -448,7 +451,6 @@
 
     @Override
     public void onLockoutPermanent() {
-        super.onLockoutPermanent();
         mLockoutCache.setLockoutModeForUser(getTargetUserId(), LockoutTracker.LOCKOUT_PERMANENT);
         // Lockout metrics are logged as an error code.
         final int error = BiometricFingerprintConstants.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
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 f4f0a19..e0393b5 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
@@ -94,7 +94,7 @@
         mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
         mMaxTemplatesPerUser = maxTemplatesPerUser;
 
-        mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
+        mALSProbeCallback = getLogger().getAmbientLightProbe(true /* startWithClient */);
 
         mEnrollReason = enrollReason;
         if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
@@ -216,7 +216,6 @@
     public void onPointerDown(int x, int y, float minor, float major) {
         try {
             mIsPointerDown = true;
-            mALSProbeCallback.getProbe().enable();
 
             final AidlSession session = getFreshDaemon();
             if (session.hasContextMethods()) {
@@ -240,7 +239,6 @@
     public void onPointerUp() {
         try {
             mIsPointerDown = false;
-            mALSProbeCallback.getProbe().disable();
 
             final AidlSession session = getFreshDaemon();
             if (session.hasContextMethods()) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 97fbb5f..0d620fd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -81,12 +81,12 @@
         super(context, lazyDaemon, token, listener, targetUserId, operationId, restricted,
                 owner, cookie, requireConfirmation, sensorId, logger, biometricContext,
                 isStrongBiometric, taskStackListener, lockoutTracker, allowBackgroundAuthentication,
-                true /* shouldVibrate */, false /* isKeyguardBypassEnabled */);
+                false /* shouldVibrate */, false /* isKeyguardBypassEnabled */);
         setRequestId(requestId);
         mLockoutFrameworkImpl = lockoutTracker;
         mSensorOverlays = new SensorOverlays(udfpsOverlayController, sidefpsController);
         mSensorProps = sensorProps;
-        mALSProbeCallback = getLogger().createALSCallback(false /* startWithClient */);
+        mALSProbeCallback = getLogger().getAmbientLightProbe(false /* startWithClient */);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index 2a59c8c..5d9af53 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -84,7 +84,7 @@
     @Override
     protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) {
         return new ClientMonitorCompositeCallback(
-                getLogger().createALSCallback(true /* startWithClient */), callback);
+                getLogger().getAmbientLightProbe(true /* startWithClient */), callback);
     }
 
     @Override
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..431be88 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1198,7 +1198,7 @@
                 mContext.unbindService(mConnection);
                 cleanupVpnStateLocked();
             } else if (mVpnRunner != null) {
-                stopVpnRunnerAndNotifyAppLocked(mPackage);
+                stopVpnRunnerAndNotifyAppLocked();
             }
 
             try {
@@ -4061,7 +4061,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 +4069,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 +4099,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/DisplayControl.java b/services/core/java/com/android/server/display/DisplayControl.java
new file mode 100644
index 0000000..e9640cf
--- /dev/null
+++ b/services/core/java/com/android/server/display/DisplayControl.java
@@ -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.server.display;
+
+import android.os.IBinder;
+
+import java.util.Objects;
+
+/**
+ * Calls into SurfaceFlinger for Display creation and deletion.
+ */
+public class DisplayControl {
+    private static native IBinder nativeCreateDisplay(String name, boolean secure);
+    private static native void nativeDestroyDisplay(IBinder displayToken);
+
+    /**
+     * Create a display in SurfaceFlinger.
+     *
+     * @param name The name of the display
+     * @param secure Whether this display is secure.
+     * @return The token reference for the display in SurfaceFlinger.
+     */
+    public static IBinder createDisplay(String name, boolean secure) {
+        Objects.requireNonNull(name, "name must not be null");
+        return nativeCreateDisplay(name, secure);
+    }
+
+    /**
+     * Destroy a display in SurfaceFlinger.
+     *
+     * @param displayToken The display token for the display to be destroyed.
+     */
+    public static void destroyDisplay(IBinder displayToken) {
+        if (displayToken == null) {
+            throw new IllegalArgumentException("displayToken must not be null");
+        }
+
+        nativeDestroyDisplay(displayToken);
+    }
+
+}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 3b627ef..12b2f47 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -159,11 +159,11 @@
  *          <displayBrightnessMapping>
  *              <displayBrightnessPoint>
  *                  <lux>50</lux>
- *                  <nits>45</nits>
+ *                  <nits>45.32</nits>
  *              </displayBrightnessPoint>
  *              <displayBrightnessPoint>
  *                  <lux>80</lux>
- *                  <nits>75</nits>
+ *                  <nits>75.43</nits>
  *              </displayBrightnessPoint>
  *          </displayBrightnessMapping>
  *      </autoBrightness>
@@ -291,19 +291,14 @@
     /**
      * Array of light sensor lux values to define our levels for auto backlight
      * brightness support.
-     * The N entries of this array define N + 1 control points as follows:
-     * (1-based arrays)
-     *
-     * Point 1:            (0, value[1]):             lux <= 0
-     * Point 2:     (level[1], value[2]):  0        < lux <= level[1]
-     * Point 3:     (level[2], value[3]):  level[2] < lux <= level[3]
-     * ...
-     * Point N+1: (level[N], value[N+1]):  level[N] < lux
-     *
+
+     * The N + 1 entries of this array define N control points defined in mBrightnessLevelsNits,
+     * with first value always being 0 lux
+
      * The control points must be strictly increasing.  Each control point
      * corresponds to an entry in the brightness backlight values arrays.
-     * For example, if lux == level[1] (first element of the levels array)
-     * then the brightness will be determined by value[2] (second element
+     * For example, if lux == level[1] (second element of the levels array)
+     * then the brightness will be determined by value[0] (first element
      * of the brightness values array).
      *
      * Spline interpolation is used to determine the auto-brightness
@@ -1094,19 +1089,21 @@
                 || autoBrightnessConfig.getDisplayBrightnessMapping() == null) {
             mBrightnessLevelsNits = getFloatArray(mContext.getResources()
                     .obtainTypedArray(com.android.internal.R.array
-                            .config_autoBrightnessDisplayValuesNits));
-            mBrightnessLevelsLux = getFloatArray(mContext.getResources()
-                    .obtainTypedArray(com.android.internal.R.array
+                            .config_autoBrightnessDisplayValuesNits), PowerManager
+                    .BRIGHTNESS_OFF_FLOAT);
+            mBrightnessLevelsLux = getLuxLevels(mContext.getResources()
+                    .getIntArray(com.android.internal.R.array
                             .config_autoBrightnessLevels));
         } else {
             final int size = autoBrightnessConfig.getDisplayBrightnessMapping()
                     .getDisplayBrightnessPoint().size();
             mBrightnessLevelsNits = new float[size];
-            mBrightnessLevelsLux = new float[size];
+            // The first control point is implicit and always at 0 lux.
+            mBrightnessLevelsLux = new float[size + 1];
             for (int i = 0; i < size; i++) {
                 mBrightnessLevelsNits[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
                         .getDisplayBrightnessPoint().get(i).getNits().floatValue();
-                mBrightnessLevelsLux[i] = autoBrightnessConfig.getDisplayBrightnessMapping()
+                mBrightnessLevelsLux[i + 1] = autoBrightnessConfig.getDisplayBrightnessMapping()
                         .getDisplayBrightnessPoint().get(i).getLux().floatValue();
             }
         }
@@ -1489,16 +1486,25 @@
      * @param array The array to convert.
      * @return the given array as a float array.
      */
-    public static float[] getFloatArray(TypedArray array) {
+    public static float[] getFloatArray(TypedArray array, float defaultValue) {
         final int n = array.length();
         float[] vals = new float[n];
         for (int i = 0; i < n; i++) {
-            vals[i] = array.getFloat(i, PowerManager.BRIGHTNESS_OFF_FLOAT);
+            vals[i] = array.getFloat(i, defaultValue);
         }
         array.recycle();
         return vals;
     }
 
+    private static float[] getLuxLevels(int[] lux) {
+        // The first control point is implicit and always at 0 lux.
+        float[] levels = new float[lux.length + 1];
+        for (int i = 0; i < lux.length; i++) {
+            levels[i + 1] = (float) lux[i];
+        }
+        return levels;
+    }
+
     static class SensorData {
         public String type;
         public String name;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 90a208e..58a182a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -413,11 +413,8 @@
 
             // For a new display, we need to initialize the default mode ID.
             if (mDefaultModeId == INVALID_MODE_ID) {
-                mDefaultModeId = mSystemPreferredModeId != INVALID_MODE_ID
-                        ? mSystemPreferredModeId : activeRecord.mMode.getModeId();
-                mDefaultModeGroup = mSystemPreferredModeId != INVALID_MODE_ID
-                        ? preferredSfDisplayMode.group
-                        : mActiveSfDisplayMode.group;
+                mDefaultModeId = activeRecord.mMode.getModeId();
+                mDefaultModeGroup = mActiveSfDisplayMode.group;
             } else if (modesAdded && activeModeChanged) {
                 Slog.d(TAG, "New display modes are added and the active mode has changed, "
                         + "use active mode as default mode.");
@@ -911,6 +908,13 @@
         public void setUserPreferredDisplayModeLocked(Display.Mode mode) {
             final int oldModeId = getPreferredModeId();
             mUserPreferredMode = mode;
+            // When clearing the user preferred mode we need to also reset the default mode. This is
+            // used by DisplayModeDirector to determine the default resolution, so if we don't clear
+            // it then the resolution won't reset to what it would've been prior to setting a user
+            // preferred display mode.
+            if (mode == null && mSystemPreferredModeId != INVALID_MODE_ID) {
+                mDefaultModeId = mSystemPreferredModeId;
+            }
             if (mode != null && (mode.isRefreshRateSet() || mode.isResolutionSet())) {
                 Display.Mode matchingSupportedMode;
                 matchingSupportedMode = findMode(mode.getPhysicalWidth(),
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 330379c..b0de844 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -305,7 +305,7 @@
                 mSurface.release();
                 mSurface = null;
             }
-            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
+            DisplayControl.destroyDisplay(getDisplayTokenLocked());
         }
 
         @Override
@@ -460,7 +460,7 @@
         public void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,
                 long presentationDeadlineNanos, int state) {
             synchronized (getSyncRoot()) {
-                IBinder displayToken = SurfaceControl.createDisplay(mName, mFlags.mSecure);
+                IBinder displayToken = DisplayControl.createDisplay(mName, mFlags.mSecure);
                 mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,
                         DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,
                         mFlags, state, surfaceTexture, mNumber) {
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 479629e..38728ce 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -82,8 +82,7 @@
     // Called with SyncRoot lock held.
     public VirtualDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener) {
-        this(syncRoot, context, handler, listener,
-                (String name, boolean secure) -> SurfaceControl.createDisplay(name, secure));
+        this(syncRoot, context, handler, listener, DisplayControl::createDisplay);
     }
 
     @VisibleForTesting
@@ -296,7 +295,7 @@
                 mSurface.release();
                 mSurface = null;
             }
-            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
+            DisplayControl.destroyDisplay(getDisplayTokenLocked());
             if (mProjection != null && mMediaProjectionCallback != null) {
                 try {
                     mProjection.unregisterCallback(mMediaProjectionCallback);
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index d632ee3..146b003 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -388,7 +388,7 @@
 
         String name = display.getFriendlyDisplayName();
         String address = display.getDeviceAddress();
-        IBinder displayToken = SurfaceControl.createDisplay(name, secure);
+        IBinder displayToken = DisplayControl.createDisplay(name, secure);
         mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
                 refreshRate, deviceFlags, address, surface);
         sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
@@ -621,7 +621,7 @@
                 mSurface.release();
                 mSurface = null;
             }
-            SurfaceControl.destroyDisplay(getDisplayTokenLocked());
+            DisplayControl.destroyDisplay(getDisplayTokenLocked());
         }
 
         public void setNameLocked(String name) {
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 366dfd1..b51f3f5 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -740,7 +740,8 @@
         mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled()
                 && !mNightDisplayTintController.isActivated()
                 && !isAccessibilityEnabled()
-                && dtm.needsLinearColorMatrix());
+                && dtm.needsLinearColorMatrix()
+                && mDisplayWhiteBalanceTintController.isAllowed());
         boolean activated = mDisplayWhiteBalanceTintController.isActivated();
 
         if (mDisplayWhiteBalanceListener != null && oldActivated != activated) {
@@ -1453,6 +1454,12 @@
      */
     public class ColorDisplayServiceInternal {
 
+        /** Sets whether DWB should be allowed in the current state. */
+        public void setDisplayWhiteBalanceAllowed(boolean allowed)  {
+            mDisplayWhiteBalanceTintController.setAllowed(allowed);
+            updateDisplayWhiteBalanceStatus();
+        }
+
         /**
          * Set the current CCT value for the display white balance transform, and if the transform
          * is enabled, apply it.
diff --git a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
index 936149c..93a78c1 100644
--- a/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
+++ b/services/core/java/com/android/server/display/color/DisplayWhiteBalanceTintController.java
@@ -61,12 +61,17 @@
     boolean mSetUp = false;
     private float[] mMatrixDisplayWhiteBalance = new float[16];
     private Boolean mIsAvailable;
+    // This feature becomes disallowed if the device is in an unsupported strong/light state.
+    private boolean mIsAllowed = true;
 
     @Override
     public void setUp(Context context, boolean needsLinear) {
         mSetUp = false;
         final Resources res = context.getResources();
 
+        // Initialize with the config value for light mode, so it starts in the right state.
+        setAllowed(res.getBoolean(R.bool.config_displayWhiteBalanceLightModeAllowed));
+
         ColorSpace.Rgb displayColorSpaceRGB = getDisplayColorSpaceFromSurfaceControl();
         if (displayColorSpaceRGB == null) {
             Slog.w(ColorDisplayService.TAG,
@@ -248,6 +253,7 @@
                     + matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3));
             pw.println("    mMatrixDisplayWhiteBalance = "
                     + matrixToString(mMatrixDisplayWhiteBalance, 4));
+            pw.println("    mIsAllowed = " + mIsAllowed);
         }
     }
 
@@ -263,6 +269,14 @@
         }
     }
 
+    public void setAllowed(boolean allowed) {
+        mIsAllowed = allowed;
+    }
+
+    public boolean isAllowed() {
+        return mIsAllowed;
+    }
+
     private ColorSpace.Rgb makeRgbColorSpaceFromXYZ(float[] redGreenBlueXYZ, float[] whiteXYZ) {
         return new ColorSpace.Rgb(
                 "Display Color Space",
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index d04b5a2..85d5b4f 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -65,6 +65,8 @@
     // this effect.
     private final float mHighLightAmbientColorTemperature;
 
+    private final boolean mLightModeAllowed;
+
     private float mAmbientColorTemperature;
     @VisibleForTesting
     float mPendingAmbientColorTemperature;
@@ -148,6 +150,8 @@
      * @param displayColorTemperatures
      *      The display color temperatures used to map the ambient color temperature to the display
      *      color temperature (or null if no mapping is necessary).
+     * @param lightModeAllowed
+     *      Whether a lighter version should be applied when Strong Mode is not enabled.
      *
      * @throws NullPointerException
      *      - brightnessSensor is null;
@@ -171,7 +175,8 @@
             float[] ambientColorTemperatures,
             float[] displayColorTemperatures,
             float[] strongAmbientColorTemperatures,
-            float[] strongDisplayColorTemperatures) {
+            float[] strongDisplayColorTemperatures,
+            boolean lightModeAllowed) {
         validateArguments(brightnessSensor, brightnessFilter, colorTemperatureSensor,
                 colorTemperatureFilter, throttler);
         mBrightnessSensor = brightnessSensor;
@@ -186,6 +191,7 @@
         mLastAmbientColorTemperature = -1.0f;
         mAmbientColorTemperatureHistory = new History(/* size= */ 50);
         mAmbientColorTemperatureOverride = -1.0f;
+        mLightModeAllowed = lightModeAllowed;
 
         try {
             mLowLightAmbientBrightnessToBiasSpline = new Spline.LinearSpline(
@@ -273,6 +279,8 @@
      */
     public void setStrongModeEnabled(boolean enabled) {
         mStrongModeEnabled = enabled;
+        mColorDisplayServiceInternal.setDisplayWhiteBalanceAllowed(mLightModeAllowed
+                || mStrongModeEnabled);
         if (mEnabled) {
             updateAmbientColorTemperature();
             updateDisplayColorTemperature();
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
index 07821b0..62f813f 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceFactory.java
@@ -95,6 +95,8 @@
         final float[] strongDisplayColorTemperatures = getFloatArray(resources,
                 com.android.internal.R.array
                 .config_displayWhiteBalanceStrongDisplayColorTemperatures);
+        final boolean lightModeAllowed = resources.getBoolean(
+                com.android.internal.R.bool.config_displayWhiteBalanceLightModeAllowed);
         final DisplayWhiteBalanceController controller = new DisplayWhiteBalanceController(
                 brightnessSensor, brightnessFilter, colorTemperatureSensor, colorTemperatureFilter,
                 throttler, displayWhiteBalanceLowLightAmbientBrightnesses,
@@ -102,7 +104,7 @@
                 displayWhiteBalanceHighLightAmbientBrightnesses,
                 displayWhiteBalanceHighLightAmbientBiases, highLightAmbientColorTemperature,
                 ambientColorTemperatures, displayColorTemperatures, strongAmbientColorTemperatures,
-                strongDisplayColorTemperatures);
+                strongDisplayColorTemperatures, lightModeAllowed);
         brightnessSensor.setCallbacks(controller);
         colorTemperatureSensor.setCallbacks(controller);
         return controller;
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 4e0489a..fee1f5c 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -110,6 +110,10 @@
     private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
     private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
 
+    // A temporary dream component that, when present, takes precedence over user configured dream
+    // component.
+    private ComponentName mSystemDreamComponent;
+
     private ComponentName mDreamOverlayServiceName;
 
     private AmbientDisplayConfiguration mDozeConfig;
@@ -352,11 +356,21 @@
         return chooseDreamForUser(doze, ActivityManager.getCurrentUser());
     }
 
+    /**
+     * If doze is true, returns the doze component for the user.
+     * Otherwise, returns the system dream component, if present.
+     * Otherwise, returns the first valid user configured dream component.
+     */
     private ComponentName chooseDreamForUser(boolean doze, int userId) {
         if (doze) {
             ComponentName dozeComponent = getDozeComponent(userId);
             return validateDream(dozeComponent) ? dozeComponent : null;
         }
+
+        if (mSystemDreamComponent != null) {
+            return mSystemDreamComponent;
+        }
+
         ComponentName[] dreams = getDreamComponentsForUser(userId);
         return dreams != null && dreams.length != 0 ? dreams[0] : null;
     }
@@ -416,6 +430,21 @@
                 userId);
     }
 
+    private void setSystemDreamComponentInternal(ComponentName componentName) {
+        synchronized (mLock) {
+            if (Objects.equals(mSystemDreamComponent, componentName)) {
+                return;
+            }
+
+            mSystemDreamComponent = componentName;
+
+            // Switch dream if currently dreaming and not dozing.
+            if (isDreamingInternal() && !mCurrentDreamIsDozing) {
+                startDreamInternal(false);
+            }
+        }
+    }
+
     private ComponentName getDefaultDreamComponentForUser(int userId) {
         String name = Settings.Secure.getStringForUser(mContext.getContentResolver(),
                 Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
@@ -668,6 +697,18 @@
         }
 
         @Override // Binder call
+        public void setSystemDreamComponent(ComponentName componentName) {
+            checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                DreamManagerService.this.setSystemDreamComponentInternal(componentName);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
         public void registerDreamOverlayService(ComponentName overlayComponent) {
             checkPermission(android.Manifest.permission.WRITE_DREAM_STATE);
 
@@ -842,6 +883,11 @@
         public ComponentName getActiveDreamComponent(boolean doze) {
             return getActiveDreamComponentInternal(doze);
         }
+
+        @Override
+        public void requestDream() {
+            requestDreamInternal();
+        }
     }
 
     private final Runnable mSystemPropertiesChanged = new Runnable() {
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 fe9e68d2..3def714f 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..6b568b7 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;
@@ -141,6 +142,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 +335,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/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 8c03ead..1d1057f 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -676,6 +676,11 @@
         return mInjector.getSettingsHelper().getIgnoreSettingsAllowlist();
     }
 
+    @Override
+    public PackageTagsList getAdasAllowlist() {
+        return mInjector.getSettingsHelper().getAdasAllowlist();
+    }
+
     @Nullable
     @Override
     public ICancellationSignal getCurrentLocation(String provider, LocationRequest request,
diff --git a/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java b/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
index 0427007..5ed0d0d 100644
--- a/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
+++ b/services/core/java/com/android/server/location/contexthub/ConcurrentLinkedEvictingDeque.java
@@ -33,7 +33,7 @@
     @Override
     public boolean add(E elem) {
         synchronized (this) {
-            if (size() == mSize) {
+            if (size() == mSize) { // TODO(b/244459069): the size() method is not constant time
                 poll();
             }
 
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
index ffdb66d..5819ff0 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientBroker.java
@@ -56,6 +56,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.location.ClientBrokerProto;
 
+import java.util.Base64;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -470,8 +471,16 @@
                         + mAttachedContextHubInfo.getId() + ")", e);
                 result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
             }
+
+            ContextHubEventLogger.getInstance().logMessageToNanoapp(
+                    mAttachedContextHubInfo.getId(),
+                    message,
+                    result == ContextHubTransaction.RESULT_SUCCESS);
         } else {
-            Log.e(TAG, "Failed to send message to nanoapp: client connection is closed");
+            String messageString = Base64.getEncoder().encodeToString(message.getMessageBody());
+            Log.e(TAG, String.format(
+                    "Failed to send message (connection closed): hostEndpointId= %1$d payload %2$s",
+                    mHostEndPointId, messageString));
             result = ContextHubTransaction.RESULT_FAILED_UNKNOWN;
         }
 
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
index 41a406c..4de7c0c 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubClientManager.java
@@ -31,9 +31,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
@@ -48,11 +45,6 @@
     private static final String TAG = "ContextHubClientManager";
 
     /*
-     * The DateFormat for printing RegistrationRecord.
-     */
-    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS");
-
-    /*
      * The maximum host endpoint ID value that a client can be assigned.
      */
     private static final int MAX_CLIENT_ID = 0x7fff;
@@ -125,14 +117,15 @@
 
         @Override
         public String toString() {
-            String out = "";
-            out += DATE_FORMAT.format(new Date(mTimestamp)) + " ";
-            out += mAction == ACTION_REGISTERED ? "+ " : "- ";
-            out += mBroker;
+            StringBuilder sb = new StringBuilder();
+            sb.append(ContextHubServiceUtil.formatDateFromTimestamp(mTimestamp));
+            sb.append(" ");
+            sb.append(mAction == ACTION_REGISTERED ? "+ " : "- ");
+            sb.append(mBroker);
             if (mAction == ACTION_CANCELLED) {
-                out += " (cancelled)";
+                sb.append(" (cancelled)");
             }
-            return out;
+            return sb.toString();
         }
     }
 
@@ -247,14 +240,17 @@
                         + message.getNanoAppId());
             }
 
-            broadcastMessage(
-                    contextHubId, message, nanoappPermissions, messagePermissions);
+            ContextHubEventLogger.getInstance().logMessageFromNanoapp(contextHubId, message, true);
+            broadcastMessage(contextHubId, message, nanoappPermissions, messagePermissions);
         } else {
             ContextHubClientBroker proxy = mHostEndPointIdToClientMap.get(hostEndpointId);
             if (proxy != null) {
-                proxy.sendMessageToClient(
-                        message, nanoappPermissions, messagePermissions);
+                ContextHubEventLogger.getInstance().logMessageFromNanoapp(contextHubId, message,
+                                                                          true);
+                proxy.sendMessageToClient(message, nanoappPermissions, messagePermissions);
             } else {
+                ContextHubEventLogger.getInstance().logMessageFromNanoapp(contextHubId, message,
+                                                                          false);
                 Log.e(TAG, "Cannot send message to unregistered client (host endpoint ID = "
                         + hostEndpointId + ")");
             }
@@ -414,17 +410,21 @@
 
     @Override
     public String toString() {
-        String out = "";
+        StringBuilder sb = new StringBuilder();
         for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
-            out += broker + "\n";
+            sb.append(broker);
+            sb.append(System.lineSeparator());
         }
 
-        out += "\nRegistration history:\n";
+        sb.append(System.lineSeparator());
+        sb.append("Registration History:");
+        sb.append(System.lineSeparator());
         Iterator<RegistrationRecord> it = mRegistrationRecordDeque.descendingIterator();
         while (it.hasNext()) {
-            out += it.next() + "\n";
+            sb.append(it.next());
+            sb.append(System.lineSeparator());
         }
 
-        return out;
+        return sb.toString();
     }
 }
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 e46bb74..15b2093 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEventLogger.java
@@ -17,6 +17,9 @@
 package com.android.server.location.contexthub;
 
 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.
@@ -30,35 +33,238 @@
  * @hide
  */
 public class ContextHubEventLogger {
+
+    /**
+     * The base class for all Context Hub events
+     */
+    public static class ContextHubEventBase {
+        /**
+         * the timestamp in milliseconds
+         */
+        public final long timeStampInMs;
+
+        /**
+         * the ID of the context hub
+         */
+        public final int contextHubId;
+
+        public ContextHubEventBase(long mTimeStampInMs, int mContextHubId) {
+            timeStampInMs = mTimeStampInMs;
+            contextHubId = mContextHubId;
+        }
+    }
+
+    /**
+     * A base class for nanoapp events
+     */
+    public static class NanoappEventBase extends ContextHubEventBase {
+        /**
+         * the ID of the nanoapp
+         */
+        public final long nanoappId;
+
+        /**
+         * whether the event was successful
+         */
+        public final boolean success;
+
+        public NanoappEventBase(long mTimeStampInMs, int mContextHubId,
+                                long mNanoappId, boolean mSuccess) {
+            super(mTimeStampInMs, mContextHubId);
+            nanoappId = mNanoappId;
+            success = mSuccess;
+        }
+    }
+
+    /**
+     * Represents a nanoapp load event
+     */
+    public static class NanoappLoadEvent extends NanoappEventBase {
+        /**
+         * the version of the nanoapp
+         */
+        public final int nanoappVersion;
+
+        /**
+         * the size in bytes of the nanoapp
+         */
+        public final long nanoappSize;
+
+        public NanoappLoadEvent(long mTimeStampInMs, int mContextHubId, long mNanoappId,
+                                int mNanoappVersion, long mNanoappSize, boolean mSuccess) {
+            super(mTimeStampInMs, mContextHubId, mNanoappId, mSuccess);
+            nanoappVersion = mNanoappVersion;
+            nanoappSize = mNanoappSize;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(ContextHubServiceUtil.formatDateFromTimestamp(timeStampInMs));
+            sb.append(": NanoappLoadEvent[hubId = ");
+            sb.append(contextHubId);
+            sb.append(", appId = 0x");
+            sb.append(Long.toHexString(nanoappId));
+            sb.append(", appVersion = ");
+            sb.append(nanoappVersion);
+            sb.append(", appSize = ");
+            sb.append(nanoappSize);
+            sb.append(" bytes, success = ");
+            sb.append(success ? "true" : "false");
+            sb.append(']');
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Represents a nanoapp unload event
+     */
+    public static class NanoappUnloadEvent extends NanoappEventBase {
+        public NanoappUnloadEvent(long mTimeStampInMs, int mContextHubId,
+                                  long mNanoappId, boolean mSuccess) {
+            super(mTimeStampInMs, mContextHubId, mNanoappId, mSuccess);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(ContextHubServiceUtil.formatDateFromTimestamp(timeStampInMs));
+            sb.append(": NanoappUnloadEvent[hubId = ");
+            sb.append(contextHubId);
+            sb.append(", appId = 0x");
+            sb.append(Long.toHexString(nanoappId));
+            sb.append(", success = ");
+            sb.append(success ? "true" : "false");
+            sb.append(']');
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Represents a nanoapp message event
+     */
+    public static class NanoappMessageEvent extends NanoappEventBase {
+        /**
+         * the message that was sent
+         */
+        public final NanoAppMessage message;
+
+        public NanoappMessageEvent(long mTimeStampInMs, int mContextHubId,
+                                   NanoAppMessage mMessage, boolean mSuccess) {
+            super(mTimeStampInMs, mContextHubId, 0, mSuccess);
+            message = mMessage;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(ContextHubServiceUtil.formatDateFromTimestamp(timeStampInMs));
+            sb.append(": NanoappMessageEvent[hubId = ");
+            sb.append(contextHubId);
+            sb.append(", ");
+            sb.append(message.toString());
+            sb.append(", success = ");
+            sb.append(success ? "true" : "false");
+            sb.append(']');
+            return sb.toString();
+        }
+    }
+
+    /**
+     * Represents a context hub restart event
+     */
+    public static class ContextHubRestartEvent extends ContextHubEventBase {
+        public ContextHubRestartEvent(long mTimeStampInMs, int mContextHubId) {
+            super(mTimeStampInMs, mContextHubId);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(ContextHubServiceUtil.formatDateFromTimestamp(timeStampInMs));
+            sb.append(": ContextHubRestartEvent[hubId = ");
+            sb.append(contextHubId);
+            sb.append(']');
+            return sb.toString();
+        }
+    }
+
+    public static final int NUM_EVENTS_TO_STORE = 20;
     private static final String TAG = "ContextHubEventLogger";
 
-    ContextHubEventLogger() {
-        throw new RuntimeException("Not implemented");
+    private final ConcurrentLinkedEvictingDeque<NanoappLoadEvent> mNanoappLoadEventQueue =
+            new ConcurrentLinkedEvictingDeque<>(NUM_EVENTS_TO_STORE);
+    private final ConcurrentLinkedEvictingDeque<NanoappUnloadEvent> mNanoappUnloadEventQueue =
+            new ConcurrentLinkedEvictingDeque<>(NUM_EVENTS_TO_STORE);
+    private final ConcurrentLinkedEvictingDeque<NanoappMessageEvent> mMessageFromNanoappQueue =
+            new ConcurrentLinkedEvictingDeque<>(NUM_EVENTS_TO_STORE);
+    private final ConcurrentLinkedEvictingDeque<NanoappMessageEvent> mMessageToNanoappQueue =
+            new ConcurrentLinkedEvictingDeque<>(NUM_EVENTS_TO_STORE);
+    private final ConcurrentLinkedEvictingDeque<ContextHubRestartEvent>
+            mContextHubRestartEventQueue = new ConcurrentLinkedEvictingDeque<>(NUM_EVENTS_TO_STORE);
+
+    // Make ContextHubEventLogger a singleton
+    private static ContextHubEventLogger sInstance = null;
+
+    private ContextHubEventLogger() {}
+
+    /**
+     * Gets the singleton instance for ContextHubEventLogger
+     */
+    public static synchronized ContextHubEventLogger getInstance() {
+        if (sInstance == null) {
+            sInstance = new ContextHubEventLogger();
+        }
+        return sInstance;
+    }
+
+    /**
+     * 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
-     * @param nanoAppId         the ID of the nanoapp
-     * @param nanoAppVersion    the version of the nanoapp
-     * @param nanoAppSize       the size in bytes of the nanoapp
+     * @param nanoappId         the ID of the nanoapp
+     * @param nanoappVersion    the version of the nanoapp
+     * @param nanoappSize       the size in bytes of the nanoapp
      * @param success           whether the load was successful
      */
-    public void logNanoAppLoad(int contextHubId, long nanoAppId, int nanoAppVersion,
-                               long nanoAppSize, boolean success) {
-        throw new RuntimeException("Not implemented");
+    public synchronized void logNanoappLoad(int contextHubId, long nanoappId, int nanoappVersion,
+                                            long nanoappSize, boolean success) {
+        long timeStampInMs = System.currentTimeMillis();
+        NanoappLoadEvent event = new NanoappLoadEvent(timeStampInMs, contextHubId, nanoappId,
+                                                      nanoappVersion, nanoappSize, success);
+        boolean status = mNanoappLoadEventQueue.add(event);
+        if (!status) {
+            Log.e(TAG, "Unable to add nanoapp load event to queue: " + event);
+        }
     }
 
     /**
      * Logs a nanoapp unload event
      *
      * @param contextHubId      the ID of the context hub
-     * @param nanoAppId         the ID of the nanoapp
+     * @param nanoappId         the ID of the nanoapp
      * @param success           whether the unload was successful
      */
-    public void logNanoAppUnload(int contextHubId, long nanoAppId, boolean success) {
-        throw new RuntimeException("Not implemented");
+    public synchronized void logNanoappUnload(int contextHubId, long nanoappId, boolean success) {
+        long timeStampInMs = System.currentTimeMillis();
+        NanoappUnloadEvent event = new NanoappUnloadEvent(timeStampInMs, contextHubId,
+                                                          nanoappId, success);
+        boolean status = mNanoappUnloadEventQueue.add(event);
+        if (!status) {
+            Log.e(TAG, "Unable to add nanoapp unload event to queue: " + event);
+        }
     }
 
     /**
@@ -66,9 +272,21 @@
      *
      * @param contextHubId      the ID of the context hub
      * @param message           the message that was sent
+     * @param success           whether the message was sent successfully
      */
-    public void logMessageFromNanoApp(int contextHubId, NanoAppMessage message) {
-        throw new RuntimeException("Not implemented");
+    public synchronized void logMessageFromNanoapp(int contextHubId, NanoAppMessage message,
+                                                   boolean success) {
+        if (message == null) {
+            return;
+        }
+
+        long timeStampInMs = System.currentTimeMillis();
+        NanoappMessageEvent event = new NanoappMessageEvent(timeStampInMs, contextHubId,
+                                                            message, success);
+        boolean status = mMessageFromNanoappQueue.add(event);
+        if (!status) {
+            Log.e(TAG, "Unable to add message from nanoapp event to queue: " + event);
+        }
     }
 
     /**
@@ -78,8 +296,19 @@
      * @param message           the message that was sent
      * @param success           whether the message was sent successfully
      */
-    public void logMessageToNanoApp(int contextHubId, NanoAppMessage message, boolean success) {
-        throw new RuntimeException("Not implemented");
+    public synchronized void logMessageToNanoapp(int contextHubId, NanoAppMessage message,
+                                                 boolean success) {
+        if (message == null) {
+            return;
+        }
+
+        long timeStampInMs = System.currentTimeMillis();
+        NanoappMessageEvent event = new NanoappMessageEvent(timeStampInMs, contextHubId,
+                                                            message, success);
+        boolean status = mMessageToNanoappQueue.add(event);
+        if (!status) {
+            Log.e(TAG, "Unable to add message to nanoapp event to queue: " + event);
+        }
     }
 
     /**
@@ -87,8 +316,13 @@
      *
      * @param contextHubId      the ID of the context hub
      */
-    public void logContextHubRestarts(int contextHubId) {
-        throw new RuntimeException("Not implemented");
+    public synchronized void logContextHubRestart(int contextHubId) {
+        long timeStampInMs = System.currentTimeMillis();
+        ContextHubRestartEvent event = new ContextHubRestartEvent(timeStampInMs, contextHubId);
+        boolean status = mContextHubRestartEventQueue.add(event);
+        if (!status) {
+            Log.e(TAG, "Unable to add Context Hub restart event to queue: " + event);
+        }
     }
 
     /**
@@ -96,8 +330,43 @@
      *
      * @return the dumped events
      */
-    public String dump() {
-        throw new RuntimeException("Not implemented");
+    public synchronized String dump() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Nanoapp Loads:");
+        sb.append(System.lineSeparator());
+        for (NanoappLoadEvent event : mNanoappLoadEventQueue) {
+            sb.append(event);
+            sb.append(System.lineSeparator());
+        }
+        sb.append(System.lineSeparator());
+        sb.append("Nanoapp Unloads:");
+        sb.append(System.lineSeparator());
+        for (NanoappUnloadEvent event : mNanoappUnloadEventQueue) {
+            sb.append(event);
+            sb.append(System.lineSeparator());
+        }
+        sb.append(System.lineSeparator());
+        sb.append("Messages from Nanoapps:");
+        sb.append(System.lineSeparator());
+        for (NanoappMessageEvent event : mMessageFromNanoappQueue) {
+            sb.append(event);
+            sb.append(System.lineSeparator());
+        }
+        sb.append(System.lineSeparator());
+        sb.append("Messages to Nanoapps:");
+        sb.append(System.lineSeparator());
+        for (NanoappMessageEvent event : mMessageToNanoappQueue) {
+            sb.append(event);
+            sb.append(System.lineSeparator());
+        }
+        sb.append(System.lineSeparator());
+        sb.append("Context Hub Restarts:");
+        sb.append(System.lineSeparator());
+        for (ContextHubRestartEvent event : mContextHubRestartEventQueue) {
+            sb.append(event);
+            sb.append(System.lineSeparator());
+        }
+        return sb.toString();
     }
 
     @Override
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 3ad5fc1..4ca0ea6 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -71,7 +71,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -172,10 +171,6 @@
 
     private final Map<Integer, AtomicLong> mLastRestartTimestampMap = new HashMap<>();
 
-    private static final int MAX_NUM_OF_NANOAPP_MESSAGE_RECORDS = 10;
-    private final ConcurrentLinkedEvictingDeque<NanoAppMessage> mNanoAppMessageRecords =
-            new ConcurrentLinkedEvictingDeque<>(MAX_NUM_OF_NANOAPP_MESSAGE_RECORDS);
-
     /**
      * Class extending the callback to register with a Context Hub.
      */
@@ -728,7 +723,6 @@
             NanoAppMessage message,
             List<String> nanoappPermissions,
             List<String> messagePermissions) {
-        mNanoAppMessageRecords.add(message);
         mClientManager.onMessageFromNanoApp(
                 contextHubId, hostEndpointId, message, nanoappPermissions, messagePermissions);
     }
@@ -791,6 +785,8 @@
                     TimeUnit.NANOSECONDS.toMillis(now - lastRestartTimeNs),
                     contextHubId);
 
+            ContextHubEventLogger.getInstance().logContextHubRestart(contextHubId);
+
             sendLocationSettingUpdate();
             sendWifiSettingUpdate(true /* forceUpdate */);
             sendAirplaneModeSettingUpdate();
@@ -1049,13 +1045,6 @@
         mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> pw.println(info));
 
         pw.println("");
-        pw.println("=================== NANOAPPS MESSAGES ====================");
-        Iterator<NanoAppMessage> iterator = mNanoAppMessageRecords.descendingIterator();
-        while (iterator.hasNext()) {
-            pw.println(iterator.next());
-        }
-
-        pw.println("");
         pw.println("=================== CLIENTS ====================");
         pw.println(mClientManager);
 
@@ -1063,6 +1052,10 @@
         pw.println("=================== TRANSACTIONS ====================");
         pw.println(mTransactionManager);
 
+        pw.println("");
+        pw.println("=================== EVENTS ====================");
+        pw.println(ContextHubEventLogger.getInstance().dump());
+
         // dump eventLog
     }
 
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index e9bf90f..f637149 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -31,6 +31,9 @@
 import android.hardware.location.NanoAppState;
 import android.util.Log;
 
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -49,6 +52,18 @@
      */
     private static final char HOST_ENDPOINT_BROADCAST = 0xFFFF;
 
+
+    /*
+     * The format for printing to logs.
+     */
+    private static final String DATE_FORMAT = "MM/dd HH:mm:ss.SSS";
+
+    /**
+     * The DateTimeFormatter for printing to logs.
+     */
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT)
+            .withZone(ZoneId.systemDefault());
+
     /**
      * Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an
      * ArrayList of HIDL ContextHub objects.
@@ -386,4 +401,15 @@
                 return ContextHubService.CONTEXT_HUB_EVENT_UNKNOWN;
         }
     }
+
+    /**
+     * Converts a timestamp in milliseconds to a properly-formatted date string for log output.
+     *
+     * @param timeStampInMs     the timestamp in milliseconds
+     * @return                  the formatted date string
+     */
+    /* package */
+    static String formatDateFromTimestamp(long timeStampInMs) {
+        return DATE_FORMATTER.format(Instant.ofEpochMilli(timeStampInMs));
+    }
 }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
index c199bb3..4f6d0d4 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubTransactionManager.java
@@ -23,11 +23,8 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
 import java.util.ArrayDeque;
 import java.util.Collections;
-import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.ScheduledFuture;
@@ -54,11 +51,6 @@
     private static final int MAX_PENDING_REQUESTS = 10000;
 
     /*
-     * The DateFormat for printing TransactionRecord.
-     */
-    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MM/dd HH:mm:ss.SSS");
-
-    /*
      * The proxy to talk to the Context Hub
      */
     private final IContextHubWrapper mContextHubProxy;
@@ -112,7 +104,7 @@
 
         @Override
         public String toString() {
-            return DATE_FORMAT.format(new Date(mTimestamp)) + " " + mTransaction;
+            return ContextHubServiceUtil.formatDateFromTimestamp(mTimestamp) + " " + mTransaction;
         }
     }
 
@@ -160,6 +152,13 @@
                             .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_LOAD,
                         toStatsTransactionResult(result));
 
+                ContextHubEventLogger.getInstance().logNanoappLoad(
+                        contextHubId,
+                        nanoAppBinary.getNanoAppId(),
+                        nanoAppBinary.getNanoAppVersion(),
+                        nanoAppBinary.getBinary().length,
+                        result == ContextHubTransaction.RESULT_SUCCESS);
+
                 if (result == ContextHubTransaction.RESULT_SUCCESS) {
                     // NOTE: The legacy JNI code used to do a query right after a load success
                     // to synchronize the service cache. Instead store the binary that was
@@ -215,6 +214,11 @@
                             .CHRE_CODE_DOWNLOAD_TRANSACTED__TRANSACTION_TYPE__TYPE_UNLOAD,
                         toStatsTransactionResult(result));
 
+                ContextHubEventLogger.getInstance().logNanoappUnload(
+                        contextHubId,
+                        nanoAppId,
+                        result == ContextHubTransaction.RESULT_SUCCESS);
+
                 if (result == ContextHubTransaction.RESULT_SUCCESS) {
                     mNanoAppStateManager.removeNanoAppInstance(contextHubId, nanoAppId);
                 }
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index 6f890cd..dc1f4ddb 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -561,7 +561,7 @@
                 mAGpsDataConnectionIpAddr = InetAddress.getByAddress(suplIpAddr);
                 if (DEBUG) Log.d(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr);
             } catch (UnknownHostException e) {
-                Log.e(TAG, "Bad IP Address: " + suplIpAddr, e);
+                Log.e(TAG, "Bad IP Address: " + Arrays.toString(suplIpAddr), e);
             }
         }
 
diff --git a/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java b/services/core/java/com/android/server/logcat/LogAccessDialogActivity.java
index 98bae3dc..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/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index 04cacee..cbbb336 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.logcat;
 
+import static android.os.Process.getParentPid;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -45,6 +47,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -340,13 +343,6 @@
      * access
      */
     private String getPackageName(LogAccessRequest request) {
-        if (mActivityManagerInternal != null) {
-            String packageName = mActivityManagerInternal.getPackageNameByPid(request.mPid);
-            if (packageName != null) {
-                return packageName;
-            }
-        }
-
         PackageManager pm = mContext.getPackageManager();
         if (pm == null) {
             // Decline the logd access if PackageManager is null
@@ -355,15 +351,28 @@
         }
 
         String[] packageNames = pm.getPackagesForUid(request.mUid);
-
         if (ArrayUtils.isEmpty(packageNames)) {
             // Decline the logd access if the app name is unknown
             Slog.e(TAG, "Unknown calling package name, declining the logd access");
             return null;
         }
 
-        String firstPackageName = packageNames[0];
+        if (mActivityManagerInternal != null) {
+            int pid = request.mPid;
+            String packageName = mActivityManagerInternal.getPackageNameByPid(pid);
+            while ((packageName == null || !ArrayUtils.contains(packageNames, packageName))
+                    && pid != -1) {
+                pid = getParentPid(pid);
+                packageName = mActivityManagerInternal.getPackageNameByPid(pid);
+            }
 
+            if (packageName != null && ArrayUtils.contains(packageNames, packageName)) {
+                return packageName;
+            }
+        }
+
+        Arrays.sort(packageNames);
+        String firstPackageName = packageNames[0];
         if (firstPackageName == null || firstPackageName.isEmpty()) {
             // Decline the logd access if the package name from uid is unknown
             Slog.e(TAG, "Unknown calling package name, declining the logd access");
diff --git a/services/core/java/com/android/server/logcat/OWNERS b/services/core/java/com/android/server/logcat/OWNERS
index 9588fa9..4ce93aa 100644
--- a/services/core/java/com/android/server/logcat/OWNERS
+++ b/services/core/java/com/android/server/logcat/OWNERS
@@ -1,5 +1,9 @@
+# Bug component: 1218649
+
 [email protected]
 [email protected]
[email protected]
 [email protected]
 [email protected]
 [email protected]
[email protected]
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index c12dc8e..9a19031 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -32,7 +32,6 @@
 import android.os.PowerWhitelistManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
-import android.util.EventLog;
 import android.util.Log;
 import android.view.KeyEvent;
 
@@ -118,12 +117,6 @@
         int componentType = getComponentType(pendingIntent);
         ComponentName componentName = getComponentName(pendingIntent, componentType);
         if (componentName != null) {
-            if (!TextUtils.equals(componentName.getPackageName(), sessionPackageName)) {
-                EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet Logging.
-                throw new IllegalArgumentException("ComponentName does not belong to "
-                        + "sessionPackageName. sessionPackageName = " + sessionPackageName
-                        + ", ComponentName pkg = " + componentName.getPackageName());
-            }
             return new MediaButtonReceiverHolder(userId, pendingIntent, componentName,
                     componentType);
         }
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 4f8771a..28c7a39 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -914,7 +914,8 @@
         }
 
         @Override
-        public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
+        public void setMediaButtonReceiver(PendingIntent pi, String sessionPackageName)
+                throws RemoteException {
             final long token = Binder.clearCallingIdentity();
             try {
                 if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
@@ -922,7 +923,7 @@
                     return;
                 }
                 mMediaButtonReceiverHolder =
-                        MediaButtonReceiverHolder.create(mContext, mUserId, pi, mPackageName);
+                        MediaButtonReceiverHolder.create(mContext, mUserId, pi, sessionPackageName);
                 mService.onMediaButtonReceiverChanged(MediaSessionRecord.this);
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -936,12 +937,11 @@
                 //mPackageName has been verified in MediaSessionService.enforcePackageName().
                 if (receiver != null && !TextUtils.equals(
                         mPackageName, receiver.getPackageName())) {
-                    EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet Logging.
+                    EventLog.writeEvent(0x534e4554, "238177121", -1, ""); // SafetyNet logging.
                     throw new IllegalArgumentException("receiver does not belong to "
                             + "package name provided to MediaSessionRecord. Pkg = " + mPackageName
                             + ", Receiver Pkg = " + receiver.getPackageName());
                 }
-
                 if ((mPolicies & MediaSessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER)
                         != 0) {
                     return;
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/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index de83f5a..d770f71 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -123,6 +123,7 @@
 import static android.telephony.CarrierConfigManager.KEY_DATA_WARNING_NOTIFICATION_BOOL;
 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -3158,7 +3159,8 @@
      * active merge set [A,B], we'd return a new template that primarily matches
      * A, but also matches B.
      */
-    private static NetworkTemplate normalizeTemplate(@NonNull NetworkTemplate template,
+    @VisibleForTesting(visibility = PRIVATE)
+    static NetworkTemplate normalizeTemplate(@NonNull NetworkTemplate template,
             @NonNull List<String[]> mergedList) {
         // Now there are several types of network which uses Subscriber Id to store network
         // information. For instance:
@@ -3168,6 +3170,12 @@
         if (template.getSubscriberIds().isEmpty()) return template;
 
         for (final String[] merged : mergedList) {
+            // In some rare cases (e.g. b/243015487), merged subscriberId list might contain
+            // duplicated items. Deduplication for better error handling.
+            final ArraySet mergedSet = new ArraySet(merged);
+            if (mergedSet.size() != merged.length) {
+                Log.wtf(TAG, "Duplicated merged list detected: " + Arrays.toString(merged));
+            }
             // TODO: Handle incompatible subscriberIds if that happens in practice.
             for (final String subscriberId : template.getSubscriberIds()) {
                 if (com.android.net.module.util.CollectionUtils.contains(merged, subscriberId)) {
@@ -3175,7 +3183,7 @@
                     // a template that matches all merged subscribers.
                     return new NetworkTemplate.Builder(template.getMatchRule())
                             .setWifiNetworkKeys(template.getWifiNetworkKeys())
-                            .setSubscriberIds(Set.of(merged))
+                            .setSubscriberIds(mergedSet)
                             .setMeteredness(template.getMeteredness())
                             .build();
                 }
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
index 5599b0c..8ce7b57 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -36,7 +36,6 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.HexDump;
@@ -45,8 +44,8 @@
 import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.GregorianCalendar;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
@@ -155,7 +154,7 @@
         try {
             final String[] packageNames = mPm.getPackagesForUid(uid);
             if (packageNames == null || packageNames.length == 0) {
-                Slog.e(TAG, "Couldn't find package: " + packageNames);
+                Slog.e(TAG, "Couldn't find package: " + Arrays.toString(packageNames));
                 return false;
             }
             ai = mPm.getApplicationInfo(packageNames[0], 0);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 5a40b30..0fac808 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1786,8 +1786,8 @@
          * from receiving events from the profile.
          */
         public boolean isPermittedForProfile(int userId) {
-            if (!mUserProfiles.isManagedProfile(userId)) {
-                return true;
+            if (!mUserProfiles.canProfileUseBoundServices(userId)) {
+                return false;
             }
             DevicePolicyManager dpm =
                     (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
@@ -1862,10 +1862,16 @@
             }
         }
 
-        public boolean isManagedProfile(int userId) {
+        public boolean canProfileUseBoundServices(int userId) {
             synchronized (mCurrentProfiles) {
                 UserInfo user = mCurrentProfiles.get(userId);
-                return user != null && user.isManagedProfile();
+                if (user == null) {
+                    return false;
+                }
+                if (user.isManagedProfile() || user.isCloneProfile()) {
+                    return false;
+                }
+                return true;
             }
         }
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index aa2a25b..0b4f736 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -304,6 +304,7 @@
 import com.android.server.notification.toast.TextToastRecord;
 import com.android.server.notification.toast.ToastRecord;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.permission.PermissionManagerServiceInternal;
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
@@ -533,6 +534,7 @@
     private UriGrantsManagerInternal mUgmInternal;
     private volatile RoleObserver mRoleObserver;
     private UserManager mUm;
+    private UserManagerInternal mUmInternal;
     private IPlatformCompat mPlatformCompat;
     private ShortcutHelper mShortcutHelper;
     private PermissionHelper mPermissionHelper;
@@ -819,7 +821,8 @@
         final List<UserInfo> activeUsers = mUm.getUsers();
         for (UserInfo userInfo : activeUsers) {
             int userId = userInfo.getUserHandle().getIdentifier();
-            if (isNASMigrationDone(userId) || mUm.isManagedProfile(userId)) {
+            if (isNASMigrationDone(userId)
+                    || userInfo.isManagedProfile() || userInfo.isCloneProfile()) {
                 continue;
             }
             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
@@ -950,7 +953,9 @@
         }
         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
         boolean migratedManagedServices = false;
-        boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
+        UserInfo userInfo = mUmInternal.getUserInfo(userId);
+        boolean ineligibleForManagedServices = forRestore &&
+                (userInfo.isManagedProfile() || userInfo.isCloneProfile());
         int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
@@ -1824,7 +1829,7 @@
             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 mUserProfiles.updateCache(context);
-                if (!mUserProfiles.isManagedProfile(userId)) {
+                if (mUserProfiles.canProfileUseBoundServices(userId)) {
                     // reload per-user settings
                     mSettingsObserver.update(null);
                     // Refresh managed services
@@ -1838,7 +1843,7 @@
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 if (userId != USER_NULL) {
                     mUserProfiles.updateCache(context);
-                    if (!mUserProfiles.isManagedProfile(userId)) {
+                    if (mUserProfiles.canProfileUseBoundServices(userId)) {
                         allowDefaultApprovedServices(userId);
                     }
                 }
@@ -1856,7 +1861,7 @@
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
                 mUserProfiles.updateCache(context);
                 mAssistants.onUserUnlocked(userId);
-                if (!mUserProfiles.isManagedProfile(userId)) {
+                if (mUserProfiles.canProfileUseBoundServices(userId)) {
                     mConditionProviders.onUserUnlocked(userId);
                     mListeners.onUserUnlocked(userId);
                     mZenModeHelper.onUserUnlocked(userId);
@@ -2218,6 +2223,7 @@
         mPackageManagerClient = packageManagerClient;
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
+        mUmInternal = LocalServices.getService(UserManagerInternal.class);
         mUsageStatsManagerInternal = usageStatsManagerInternal;
         mAppOps = appOps;
         mAppOpsService = iAppOps;
@@ -4946,7 +4952,16 @@
             }
             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
 
-            return mZenModeHelper.addAutomaticZenRule(pkg, automaticZenRule,
+            // If the caller is system, take the package name from the rule's owner rather than
+            // from the caller's package.
+            String rulePkg = pkg;
+            if (isCallingUidSystem()) {
+                if (automaticZenRule.getOwner() != null) {
+                    rulePkg = automaticZenRule.getOwner().getPackageName();
+                }
+            }
+
+            return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
                     "addAutomaticZenRule");
         }
 
@@ -6295,21 +6310,40 @@
             checkCallerIsSystem();
             mHandler.post(() -> {
                 synchronized (mNotificationLock) {
-                    // strip flag from all enqueued notifications. listeners will be informed
-                    // in post runnable.
-                    List<NotificationRecord> enqueued = findNotificationsByListLocked(
-                            mEnqueuedNotifications, pkg, null, notificationId, userId);
-                    for (int i = 0; i < enqueued.size(); i++) {
-                        removeForegroundServiceFlagLocked(enqueued.get(i));
+                    int count = getNotificationCount(pkg, userId);
+                    boolean removeFgsNotification = false;
+                    if (count > MAX_PACKAGE_NOTIFICATIONS) {
+                        mUsageStats.registerOverCountQuota(pkg);
+                        removeFgsNotification = true;
                     }
+                    if (removeFgsNotification) {
+                        NotificationRecord r = findNotificationLocked(pkg, null, notificationId,
+                                userId);
+                        if (r != null) {
+                            if (DBG) {
+                                Slog.d(TAG, "Remove FGS flag not allow. Cancel FGS notification");
+                            }
+                            removeFromNotificationListsLocked(r);
+                            cancelNotificationLocked(r, false, REASON_APP_CANCEL, true,
+                                    null, SystemClock.elapsedRealtime());
+                        }
+                    } else {
+                        // strip flag from all enqueued notifications. listeners will be informed
+                        // in post runnable.
+                        List<NotificationRecord> enqueued = findNotificationsByListLocked(
+                                mEnqueuedNotifications, pkg, null, notificationId, userId);
+                        for (int i = 0; i < enqueued.size(); i++) {
+                            removeForegroundServiceFlagLocked(enqueued.get(i));
+                        }
 
-                    // if posted notification exists, strip its flag and tell listeners
-                    NotificationRecord r = findNotificationByListLocked(
-                            mNotificationList, pkg, null, notificationId, userId);
-                    if (r != null) {
-                        removeForegroundServiceFlagLocked(r);
-                        mRankingHelper.sort(mNotificationList);
-                        mListeners.notifyPostedLocked(r, r);
+                        // if posted notification exists, strip its flag and tell listeners
+                        NotificationRecord r = findNotificationByListLocked(
+                                mNotificationList, pkg, null, notificationId, userId);
+                        if (r != null) {
+                            removeForegroundServiceFlagLocked(r);
+                            mRankingHelper.sort(mNotificationList);
+                            mListeners.notifyPostedLocked(r, r);
+                        }
                     }
                 }
             });
@@ -7006,6 +7040,29 @@
         return mPermissionHelper.hasPermission(uid);
     }
 
+    private int getNotificationCount(String pkg, int userId) {
+        int count = 0;
+        synchronized (mNotificationLock) {
+            final int numListSize = mNotificationList.size();
+            for (int i = 0; i < numListSize; i++) {
+                final NotificationRecord existing = mNotificationList.get(i);
+                if (existing.getSbn().getPackageName().equals(pkg)
+                        && existing.getSbn().getUserId() == userId) {
+                    count++;
+                }
+            }
+            final int numEnqSize = mEnqueuedNotifications.size();
+            for (int i = 0; i < numEnqSize; i++) {
+                final NotificationRecord existing = mEnqueuedNotifications.get(i);
+                if (existing.getSbn().getPackageName().equals(pkg)
+                        && existing.getSbn().getUserId() == userId) {
+                    count++;
+                }
+            }
+        }
+        return count;
+    }
+
     protected int getNotificationCount(String pkg, int userId, int excludedId,
             String excludedTag) {
         int count = 0;
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..ba71438 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;
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index dade7aa..ae305ca 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;
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..71593e10 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 6cfe093..3fb4066 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -74,12 +74,11 @@
 import com.android.server.pm.dex.ArtManagerService;
 import com.android.server.pm.dex.ArtStatsLogUtils;
 import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
-import com.android.server.pm.dex.DexManager;
 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;
@@ -787,10 +786,7 @@
      */
     private String getRealCompilerFilter(ApplicationInfo info, String targetCompilerFilter,
             boolean isUsedByOtherApps) {
-        // When an app or priv app is configured to run out of box, only verify it.
-        if (info.isEmbeddedDexUsed()
-                || (info.isPrivilegedApp()
-                && DexManager.isPackageSelectedToRunOob(info.packageName))) {
+        if (info.isEmbeddedDexUsed()) {
             return "verify";
         }
 
@@ -827,10 +823,7 @@
      * handling the case where the package code is used by other apps.
      */
     private String getRealCompilerFilter(AndroidPackage pkg, String targetCompilerFilter) {
-        // When an app or priv app is configured to run out of box, only verify it.
-        if (pkg.isUseEmbeddedDex()
-                || (pkg.isPrivileged()
-                    && DexManager.isPackageSelectedToRunOob(pkg.getPackageName()))) {
+        if (pkg.isUseEmbeddedDex()) {
             return "verify";
         }
 
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 8f255fa..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);
     }
 
@@ -741,6 +740,12 @@
         return snapshot().checkUidSignaturesForAllUsers(uid1, uid2);
     }
 
+    @Override
+    public void setPackageStoppedState(@NonNull String packageName, boolean stopped,
+            int userId) {
+        mService.setPackageStoppedState(snapshot(), packageName, stopped, userId);
+    }
+
     @NonNull
     @Override
     @Deprecated
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5ad39f2..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;
@@ -5801,6 +5802,11 @@
             final Computer snapshot = snapshotComputer();
             enforceOwnerRights(snapshot, packageName, Binder.getCallingUid());
             mimeTypes = CollectionUtils.emptyIfNull(mimeTypes);
+            for (String mimeType : mimeTypes) {
+                if (mimeType.length() > 255) {
+                    throw new IllegalArgumentException("MIME type length exceeds 255 characters");
+                }
+            }
             final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
             Set<String> existingMimeTypes = packageState.getMimeGroups().get(mimeGroup);
             if (existingMimeTypes == null) {
@@ -5811,6 +5817,10 @@
                     && existingMimeTypes.containsAll(mimeTypes)) {
                 return;
             }
+            if (mimeTypes.size() > 500) {
+                throw new IllegalStateException("Max limit on MIME types for MIME group "
+                        + mimeGroup + " exceeded for package " + packageName);
+            }
 
             ArraySet<String> mimeTypesSet = new ArraySet<>(mimeTypes);
             commitPackageStateMutation(null, packageName, packageStateWrite -> {
@@ -6707,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 b7ab381..77334e5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -41,6 +41,7 @@
 import android.compat.annotation.EnabledSince;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
@@ -92,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;
@@ -1125,13 +1126,18 @@
                 throw new IllegalArgumentException("Unsupported component type");
             }
 
-            if (comp.getIntents().isEmpty()) {
+            if (comp == null || comp.getIntents().isEmpty()) {
                 continue;
             }
 
-            final boolean match = comp.getIntents().stream().anyMatch(
-                    f -> IntentResolver.intentMatchesFilter(f.getIntentFilter(), intent,
-                            resolvedType));
+            boolean match = false;
+            for (int j = 0, size = comp.getIntents().size(); j < size; ++j) {
+                IntentFilter intentFilter = comp.getIntents().get(j).getIntentFilter();
+                if (IntentResolver.intentMatchesFilter(intentFilter, intent, resolvedType)) {
+                    match = true;
+                    break;
+                }
+            }
             if (!match) {
                 Slog.w(TAG, "Intent does not match component's intent filter: " + intent);
                 Slog.w(TAG, "Access blocked: " + comp.getComponentName());
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index da89b9e..7faebb5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3044,7 +3044,12 @@
                 translateUserId(userId, UserHandle.USER_NULL, "runSetUserRestriction");
         final IUserManager um = IUserManager.Stub.asInterface(
                 ServiceManager.getService(Context.USER_SERVICE));
-        um.setUserRestriction(restriction, value, translatedUserId);
+        try {
+            um.setUserRestriction(restriction, value, translatedUserId);
+        } catch (IllegalArgumentException e) {
+            getErrPrintWriter().println(e.getMessage());
+            return 1;
+        }
         return 0;
     }
 
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]\[email protected](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]\[email protected](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..3bb5a1b6 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 f09e137..fada577 100644
--- a/services/core/java/com/android/server/pm/ResolveIntentHelper.java
+++ b/services/core/java/com/android/server/pm/ResolveIntentHelper.java
@@ -54,7 +54,7 @@
 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;
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/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index f2bcf5e..0b20683 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -280,6 +280,7 @@
 
     private final Object mLock = new Object();
     private final Object mNonPersistentUsersLock = new Object();
+    private final Object mWtfLock = new Object();
 
     private static List<ResolveInfo> EMPTY_RESOLVE_INFO = new ArrayList<>(0);
 
@@ -444,10 +445,10 @@
     @interface ShortcutOperation {
     }
 
-    @GuardedBy("mLock")
+    @GuardedBy("mWtfLock")
     private int mWtfCount = 0;
 
-    @GuardedBy("mLock")
+    @GuardedBy("mWtfLock")
     private Exception mLastWtfStacktrace;
 
     @GuardedBy("mLock")
@@ -4727,13 +4728,15 @@
 
                 mStatLogger.dump(pw, "  ");
 
-                pw.println();
-                pw.print("  #Failures: ");
-                pw.println(mWtfCount);
+                synchronized (mWtfLock) {
+                    pw.println();
+                    pw.print("  #Failures: ");
+                    pw.println(mWtfCount);
 
-                if (mLastWtfStacktrace != null) {
-                    pw.print("  Last failure stack trace: ");
-                    pw.println(Log.getStackTraceString(mLastWtfStacktrace));
+                    if (mLastWtfStacktrace != null) {
+                        pw.print("  Last failure stack trace: ");
+                        pw.println(Log.getStackTraceString(mLastWtfStacktrace));
+                    }
                 }
 
                 pw.println();
@@ -5148,7 +5151,7 @@
         if (e == null) {
             e = new RuntimeException("Stacktrace");
         }
-        synchronized (mLock) {
+        synchronized (mWtfLock) {
             mWtfCount++;
             mLastWtfStacktrace = new Exception("Last failure was logged here:");
         }
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/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 9c74dd7..a622d07 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -32,6 +32,15 @@
       ]
     },
     {
+      "file_patterns": ["(/|^)PackageManagerService\\.java","(/|^)UserManagerService\\.java"],
+      "name": "CtsAppCloningDeviceTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
       "name": "CtsShortcutHostTestCases",
       "file_patterns": ["(/|^)ShortcutService\\.java"]
     },
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 297439f..4f5fd02 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.
@@ -313,12 +322,61 @@
      */
     public abstract @Nullable UserProperties getUserProperties(@UserIdInt int userId);
 
-    /** TODO(b/239982558): add javadoc / mention invalid_id is used to unassing */
+    /**
+     * Assigns a user to a display.
+     *
+     * <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
+     * started and it doesn't validate if the display exists.
+     *
+     */
     public abstract void assignUserToDisplay(@UserIdInt int userId, int displayId);
 
     /**
+     * Unassigns a user from its current display.
+     *
+     * <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.
+     */
+    public abstract void unassignUserFromDisplay(@UserIdInt int userId);
+
+    /**
+     * Returns {@code true} if the user is visible (as defined by
+     * {@link UserManager#isUserVisible()}.
+     */
+    public abstract boolean isUserVisible(@UserIdInt int userId);
+
+    /**
      * Returns {@code true} if the user is visible (as defined by
      * {@link UserManager#isUserVisible()} in the given display.
      */
     public abstract boolean isUserVisible(@UserIdInt int userId, int displayId);
+
+    /**
+     * 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
+     * {@link android.view.Display#DEFAULT_DISPLAY default display}, while other users would only be
+     * 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.
+     */
+    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 be associated with the user that was
+     * started with {@code ActivityManager.startUserInBackgroundOnSecondaryDisplay()}.
+     */
+    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 d8b7fda..07ec80b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -173,6 +173,8 @@
 
     private static final String LOG_TAG = "UserManagerService";
     static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
+    // For Multiple Users on Multiple Displays
+    static final boolean DBG_MUMD = false; // DO NOT SUBMIT WITH TRUE
     private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
     // Can be used for manual testing of id recycling
     private static final boolean RELEASE_DELETED_USER_ID = false; // DO NOT SUBMIT WITH TRUE
@@ -303,6 +305,7 @@
 
     private PackageManagerInternal mPmInternal;
     private DevicePolicyManagerInternal mDevicePolicyManagerInternal;
+    private ActivityManagerInternal mAmInternal;
 
     /** Indicates that this is the 1st boot after the system user mode was changed by emulation. */
     private boolean mUpdatingSystemUserMode;
@@ -381,7 +384,7 @@
     }
 
     @GuardedBy("mUsersLock")
-    private final SparseArray<UserData> mUsers = new SparseArray<>();
+    private final SparseArray<UserData> mUsers;
 
     /**
      * Map of user type names to their corresponding {@link UserTypeDetails}.
@@ -625,14 +628,13 @@
     private final WatchedUserStates mUserStates = new WatchedUserStates();
 
     /**
-     * Used on devices that support background users (key) running on secondary displays (value).
-     *
-     * <p>Is {@code null} by default and instantiated on demand when the users are started on
-     * secondary displays.
+     * Set on on devices that support background users (key) running on secondary displays (value).
      */
+    // TODO(b/244644281): move such logic to a different class (like UserDisplayAssigner)
     @Nullable
-    @GuardedBy("mUsersLock")
-    private SparseIntArray mUsersOnSecondaryDisplays;
+    @GuardedBy("mUsersOnSecondaryDisplays")
+    private final SparseIntArray mUsersOnSecondaryDisplays;
+    private final boolean mUsersOnSecondaryDisplaysEnabled;
 
     private static UserManagerService sInstance;
 
@@ -704,10 +706,12 @@
         }
     }
 
-    // TODO b/28848102 Add support for test dependencies injection
+    // TODO(b/28848102) Add support for test dependencies injection
     @VisibleForTesting
     UserManagerService(Context context) {
-        this(context, null, null, new Object(), context.getCacheDir());
+        this(context, /* pm= */ null, /* userDataPreparer= */ null,
+                /* packagesLock= */ new Object(), context.getCacheDir(), /* users= */ null,
+                /* usersOnSecondaryDisplays= */ null);
     }
 
     /**
@@ -717,14 +721,18 @@
      */
     UserManagerService(Context context, PackageManagerService pm, UserDataPreparer userDataPreparer,
             Object packagesLock) {
-        this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory());
+        this(context, pm, userDataPreparer, packagesLock, Environment.getDataDirectory(),
+                /* users= */ null, /* usersOnSecondaryDisplays= */ null);
     }
 
-    private UserManagerService(Context context, PackageManagerService pm,
-            UserDataPreparer userDataPreparer, Object packagesLock, File dataDir) {
+    @VisibleForTesting
+    UserManagerService(Context context, PackageManagerService pm,
+            UserDataPreparer userDataPreparer, Object packagesLock, File dataDir,
+            SparseArray<UserData> users, @Nullable SparseIntArray usersOnSecondaryDisplays) {
         mContext = context;
         mPm = pm;
         mPackagesLock = packagesLock;
+        mUsers = users != null ? users : new SparseArray<>();
         mHandler = new MainHandler();
         mUserDataPreparer = userDataPreparer;
         mUserTypes = UserTypeFactory.getUserTypes();
@@ -750,6 +758,14 @@
         mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
         mUser0Allocations = DBG_ALLOCATION ? new AtomicInteger() : null;
         emulateSystemUserModeIfNeeded();
+        mUsersOnSecondaryDisplaysEnabled = UserManager.isUsersOnSecondaryDisplaysEnabled();
+        if (mUsersOnSecondaryDisplaysEnabled) {
+            mUsersOnSecondaryDisplays = usersOnSecondaryDisplays == null
+                    ? new SparseIntArray() // default behavior
+                    : usersOnSecondaryDisplays; // passed by unit test
+        } else {
+            mUsersOnSecondaryDisplays = null;
+        }
     }
 
     void systemReady() {
@@ -1083,9 +1099,20 @@
     @Override
     public int getProfileParentId(@UserIdInt int userId) {
         checkManageUsersPermission("get the profile parent");
-        return mLocalService.getProfileParentId(userId);
+        return getProfileParentIdUnchecked(userId);
     }
 
+    private @UserIdInt int getProfileParentIdUnchecked(@UserIdInt int userId) {
+        synchronized (mUsersLock) {
+            UserInfo profileParent = getProfileParentLU(userId);
+            if (profileParent == null) {
+                return userId;
+            }
+            return profileParent.id;
+        }
+    }
+
+
     @GuardedBy("mUsersLock")
     private UserInfo getProfileParentLU(@UserIdInt int userId) {
         UserInfo profile = getUserInfoLU(userId);
@@ -1360,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);
         }
     }
 
@@ -1697,8 +1729,12 @@
                     + ") is running in the foreground");
         }
 
-        int currentUser = Binder.withCleanCallingIdentity(() -> ActivityManager.getCurrentUser());
-        return currentUser == userId;
+        return userId == getCurrentUserId();
+    }
+
+    @VisibleForTesting
+    boolean isUsersOnSecondaryDisplaysEnabled() {
+        return mUsersOnSecondaryDisplaysEnabled;
     }
 
     @Override
@@ -1714,32 +1750,109 @@
         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;
         }
 
-        // TODO(b/239824814): STOPSHIP - add CTS tests (requires change on testing infra)
-        synchronized (mUsersLock) {
-            if (mUsersOnSecondaryDisplays != null) {
-                // TODO(b/239824814): make sure it handles profile as well
-                return (mUsersOnSecondaryDisplays.indexOfKey(userId) >= 0);
+        // Device doesn't support multiple users on multiple displays, so only users checked above
+        // can be visible
+        if (!mUsersOnSecondaryDisplaysEnabled) {
+            return false;
+        }
+
+        synchronized (mUsersOnSecondaryDisplays) {
+            return mUsersOnSecondaryDisplays.indexOfKey(userId) >= 0;
+        }
+    }
+
+    @VisibleForTesting
+    int getDisplayAssignedToUser(@UserIdInt int userId) {
+        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
+            return Display.DEFAULT_DISPLAY;
+        }
+
+        if (!mUsersOnSecondaryDisplaysEnabled) {
+            return Display.INVALID_DISPLAY;
+        }
+
+        synchronized (mUsersOnSecondaryDisplays) {
+            return mUsersOnSecondaryDisplays.get(userId, Display.INVALID_DISPLAY);
+        }
+    }
+
+    @VisibleForTesting
+    int getUserAssignedToDisplay(int displayId) {
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            return getCurrentUserId();
+        }
+
+        if (!mUsersOnSecondaryDisplaysEnabled) {
+            int currentUserId = getCurrentUserId();
+            Slogf.w(LOG_TAG, "getUsersAssignedToDisplay(%d) called with non-DEFAULT_DISPLAY on "
+                    + "system that doesn't support that; returning current user (%d)", displayId,
+                    currentUserId);
+            return currentUserId;
+        }
+
+        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);
+                }
             }
         }
 
-        return false;
+        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;
     }
 
-    private boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) {
-        int currentUserId = Binder.withCleanCallingIdentity(() -> ActivityManager.getCurrentUser());
+    /**
+     * Gets the current user id, calling {@link ActivityManagerInternal} directly (and without
+     * performing any permission check).
+     *
+     * @return id of current foreground user, or {@link UserHandle#USER_NULL} if
+     * {@link ActivityManagerInternal} is not available yet.
+     */
+    @VisibleForTesting
+    int getCurrentUserId() {
+        ActivityManagerInternal activityManagerInternal = getActivityManagerInternal();
+        if (activityManagerInternal == null) {
+            Slog.w(LOG_TAG, "getCurrentUserId() called too early, ActivityManagerInternal"
+                    + " is not set yet");
+            return UserHandle.USER_NULL;
+        }
+        return activityManagerInternal.getCurrentUserId();
+    }
+
+    /**
+     * Gets whether the user is the current foreground user or a started profile of that user.
+     *
+     * <p>Doesn't perform any permission check.
+     */
+    @VisibleForTesting
+    boolean isCurrentUserOrRunningProfileOfCurrentUser(@UserIdInt int userId) {
+        int currentUserId = getCurrentUserId();
 
         if (currentUserId == userId) {
             return true;
         }
 
-        if (isProfile(userId)) {
-            int parentId = Binder.withCleanCallingIdentity(() -> getProfileParentId(userId));
+        if (isProfileUnchecked(userId)) {
+            int parentId = getProfileParentIdUnchecked(userId);
             if (parentId == currentUserId) {
                 return isUserRunning(userId);
             }
@@ -1748,18 +1861,53 @@
         return false;
     }
 
-    // TODO(b/239982558): currently used just by shell command, might need to move to
-    // UserManagerInternal if needed by other components (like WindowManagerService)
-    // TODO(b/239982558): add unit test
-    // TODO(b/239982558): try to merge with isUserVisibleUnchecked()
+    // 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) {
-        if (displayId == Display.DEFAULT_DISPLAY) {
+        if (displayId == Display.INVALID_DISPLAY) {
+            return false;
+        }
+        if (!mUsersOnSecondaryDisplaysEnabled) {
             return isCurrentUserOrRunningProfileOfCurrentUser(userId);
         }
-        synchronized (mUsersLock) {
-            // TODO(b/239824814): make sure it handles profile as well
-            return mUsersOnSecondaryDisplays != null && mUsersOnSecondaryDisplays.get(userId,
-                    Display.INVALID_DISPLAY) == displayId;
+
+        // 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) {
+            return mUsersOnSecondaryDisplays.get(userId, Display.INVALID_DISPLAY) == displayId;
         }
     }
 
@@ -2601,6 +2749,11 @@
         if (!UserRestrictionsUtils.isValidRestriction(key)) {
             return;
         }
+
+        if (!userExists(userId)) {
+            throw new IllegalArgumentException("Cannot set user restriction. "
+                    + "User with this id does not exist");
+        }
         synchronized (mRestrictionsLock) {
             // Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create
             // a copy.
@@ -3185,6 +3338,22 @@
     }
 
     /**
+     * Checks whether user with a given ID exists.
+     * @param id User id to be checked.
+     */
+    @VisibleForTesting
+    boolean userExists(int id) {
+        synchronized (mUsersLock) {
+            for (int userId : mUserIds) {
+                if (userId == id) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns an array of user ids, including pre-created users.
      *
      * <p>This method should only used for the specific cases that need to handle pre-created users;
@@ -3707,7 +3876,6 @@
             }
         }
 
-        updateUserIds();
         initDefaultGuestRestrictions();
 
         writeUserLP(userData);
@@ -4730,7 +4898,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) {
@@ -4904,6 +5074,7 @@
         synchronized (mUsersLock) {
             mUsers.put(userInfo.id, userData);
         }
+        updateUserIds();
         return userData;
     }
 
@@ -5051,7 +5222,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             final UserData userData;
-            int currentUser = ActivityManager.getCurrentUser();
+            int currentUser = getCurrentUserId();
             if (currentUser == userId) {
                 Slog.w(LOG_TAG, "Current user cannot be removed.");
                 return false;
@@ -5179,7 +5350,7 @@
                 }
 
                 // Attempt to immediately remove a non-current user
-                final int currentUser = ActivityManager.getCurrentUser();
+                final int currentUser = getCurrentUserId();
                 if (currentUser != userId) {
                     // Attempt to remove the user. This will fail if the user is the current user
                     if (removeUserUnchecked(userId)) {
@@ -5329,6 +5500,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
@@ -5346,12 +5528,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));
@@ -5362,7 +5544,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(
@@ -5980,11 +6162,10 @@
             return;
         }
 
-        final ActivityManagerInternal amInternal = LocalServices
-                .getService(ActivityManagerInternal.class);
+        final int currentUserId = getCurrentUserId();
         pw.print("Current user: ");
-        if (amInternal != null) {
-            pw.println(amInternal.getCurrentUserId());
+        if (currentUserId != UserHandle.USER_NULL) {
+            pw.println(currentUserId);
         } else {
             pw.println("N/A");
         }
@@ -6042,11 +6223,14 @@
         } // synchronized (mPackagesLock)
 
         // Multiple Users on Multiple Display info
-        pw.println("  Supports users on secondary displays: "
+        pw.println("  Supports users on secondary displays: " + mUsersOnSecondaryDisplaysEnabled);
+        // mUsersOnSecondaryDisplaysEnabled is set on constructor, while the UserManager API is
+        // set dynamically, so print both to help cases where the developer changed it on the fly
+        pw.println("  UM.isUsersOnSecondaryDisplaysEnabled(): "
                 + UserManager.isUsersOnSecondaryDisplaysEnabled());
-        synchronized (mUsersLock) {
-            if (mUsersOnSecondaryDisplays != null) {
-                pw.print("  Users on secondary displays: ");
+        if (mUsersOnSecondaryDisplaysEnabled) {
+            pw.print("  Users on secondary displays: ");
+            synchronized (mUsersOnSecondaryDisplays) {
                 pw.println(mUsersOnSecondaryDisplays);
             }
         }
@@ -6108,13 +6292,13 @@
     private void dumpUser(PrintWriter pw, @UserIdInt int userId, StringBuilder sb, long now,
             long nowRealtime) {
         if (userId == UserHandle.USER_CURRENT) {
-            final ActivityManagerInternal amInternal = LocalServices
-                    .getService(ActivityManagerInternal.class);
-            if (amInternal == null) {
+            final int currentUserId = getCurrentUserId();
+            pw.print("Current user: ");
+            if (currentUserId == UserHandle.USER_NULL) {
                 pw.println("Cannot determine current user");
                 return;
             }
-            userId = amInternal.getCurrentUserId();
+            userId = currentUserId;
         }
 
         synchronized (mUsersLock) {
@@ -6360,7 +6544,7 @@
 
         @Override
         public void removeAllUsers() {
-            if (UserHandle.USER_SYSTEM == ActivityManager.getCurrentUser()) {
+            if (UserHandle.USER_SYSTEM == getCurrentUserId()) {
                 // Remove the non-system users straight away.
                 removeNonSystemUsers();
             } else {
@@ -6420,9 +6604,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
@@ -6542,13 +6731,7 @@
 
         @Override
         public int getProfileParentId(@UserIdInt int userId) {
-            synchronized (mUsersLock) {
-                UserInfo profileParent = getProfileParentLU(userId);
-                if (profileParent == null) {
-                    return userId;
-                }
-                return profileParent.id;
-            }
+            return getProfileParentIdUnchecked(userId);
         }
 
         @Override
@@ -6616,85 +6799,116 @@
 
         @Override
         public void assignUserToDisplay(int userId, int displayId) {
-            if (DBG) {
-                Slogf.d(LOG_TAG, "assignUserToDisplay(%d, %d): mUsersOnSecondaryDisplays=%s",
-                        userId, displayId, mUsersOnSecondaryDisplays);
+            if (DBG_MUMD) {
+                Slogf.d(LOG_TAG, "assignUserToDisplay(%d, %d)", userId, displayId);
             }
-            // TODO(b/240613396) throw exception if feature not supported
 
-            if (displayId == Display.INVALID_DISPLAY) {
-                synchronized (mUsersLock) {
-                    if (mUsersOnSecondaryDisplays == null) {
-                        if (false) {
-                            // TODO(b/240613396): remove this if once we check for support above
-                            Slogf.wtf(LOG_TAG, "assignUserToDisplay(%d, %d): no "
-                                    + "mUsersOnSecondaryDisplays", userId, displayId);
-                        }
-                        return;
-                    }
-                    if (DBG) {
-                        Slogf.d(LOG_TAG, "Removing %d from mUsersOnSecondaryDisplays", userId);
-                    }
-                    mUsersOnSecondaryDisplays.delete(userId);
-                    if (mUsersOnSecondaryDisplays.size() == 0) {
-                        if (DBG) {
-                            Slogf.d(LOG_TAG, "Removing mUsersOnSecondaryDisplays");
-                        }
-                        mUsersOnSecondaryDisplays = null;
-                    }
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                // Don't need to do anything because methods (such as isUserVisible()) already know
+                // that the current user (and their profiles) is assigned to the default display.
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "ignoring on default display");
                 }
                 return;
             }
 
-            synchronized (mUsersLock) {
-                if (mUsersOnSecondaryDisplays == null) {
-                    if (DBG) {
-                        Slogf.d(LOG_TAG, "Creating mUsersOnSecondaryDisplays");
-                    }
-                    mUsersOnSecondaryDisplays = new SparseIntArray();
-                }
-                if (DBG) {
-                    Slogf.d(LOG_TAG, "Adding %d->%d to mUsersOnSecondaryDisplays",
-                            userId, displayId);
-                }
+            if (!mUsersOnSecondaryDisplaysEnabled) {
+                throw new UnsupportedOperationException("assignUserToDisplay(" + userId + ", "
+                        + displayId + ") called on device that doesn't support multiple "
+                        + "users on multiple displays");
+            }
 
+            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 (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++) {
+                    // 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
+                }
+
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "Adding full user %d -> display %d", userId, displayId);
+                }
                 mUsersOnSecondaryDisplays.put(userId, displayId);
             }
         }
 
         @Override
+        public void unassignUserFromDisplay(@UserIdInt int userId) {
+            if (DBG_MUMD) {
+                Slogf.d(LOG_TAG, "unassignUserFromDisplay(%d)", userId);
+            }
+            if (!mUsersOnSecondaryDisplaysEnabled) {
+                // Don't need to do anything because methods (such as isUserVisible()) already know
+                // that the current user (and their profiles) is assigned to the default display.
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "ignoring when device doesn't support MUMD");
+                }
+                return;
+            }
+
+            synchronized (mUsersOnSecondaryDisplays) {
+                if (DBG_MUMD) {
+                    Slogf.d(LOG_TAG, "Removing %d from mUsersOnSecondaryDisplays (%s)", userId,
+                            mUsersOnSecondaryDisplays);
+                }
+                mUsersOnSecondaryDisplays.delete(userId);
+            }
+        }
+
+        @Override
+        public boolean isUserVisible(int userId) {
+            return isUserVisibleUnchecked(userId);
+        }
+
+        @Override
         public boolean isUserVisible(int userId, int displayId) {
             return isUserVisibleOnDisplay(userId, displayId);
         }
+
+        @Override
+        public int getDisplayAssignedToUser(int userId) {
+            return UserManagerService.this.getDisplayAssignedToUser(userId);
+        }
+
+        @Override
+        public int getUserAssignedToDisplay(int displayId) {
+            return UserManagerService.this.getUserAssignedToDisplay(displayId);
+        }
     } // class LocalService
 
     /**
@@ -6856,4 +7070,12 @@
         }
         return mDevicePolicyManagerInternal;
     }
+
+    /** Returns the internal activity manager interface. */
+    private @Nullable ActivityManagerInternal getActivityManagerInternal() {
+        if (mAmInternal == null) {
+            mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
+        }
+        return mAmInternal;
+    }
 }
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/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 17109e9..8c2da45 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -36,7 +36,6 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.util.Log;
@@ -58,8 +57,6 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -81,10 +78,6 @@
     private static final String TAG = "DexManager";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB = "pm.dexopt.priv-apps-oob";
-    private static final String PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST =
-            "pm.dexopt.priv-apps-oob-list";
-
     // System server cannot load executable code outside system partitions.
     // However it can load verification data - thus we pick the "verify" compiler filter.
     private static final String SYSTEM_SERVER_COMPILER_FILTER = "verify";
@@ -910,45 +903,6 @@
     }
 
     /**
-     * Returns whether the given package is in the list of privilaged apps that should run out of
-     * box. This only makes sense if the feature is enabled. Note that when the the OOB list is
-     * empty, all priv apps will run in OOB mode.
-     */
-    public static boolean isPackageSelectedToRunOob(String packageName) {
-        return isPackageSelectedToRunOob(Arrays.asList(packageName));
-    }
-
-    /**
-     * Returns whether any of the given packages are in the list of privilaged apps that should run
-     * out of box. This only makes sense if the feature is enabled. Note that when the the OOB list
-     * is empty, all priv apps will run in OOB mode.
-     */
-    public static boolean isPackageSelectedToRunOob(Collection<String> packageNamesInSameProcess) {
-        return isPackageSelectedToRunOobInternal(
-                SystemProperties.getBoolean(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB, false),
-                SystemProperties.get(PROPERTY_NAME_PM_DEXOPT_PRIV_APPS_OOB_LIST, "ALL"),
-                packageNamesInSameProcess);
-    }
-
-    @VisibleForTesting
-    /* package */ static boolean isPackageSelectedToRunOobInternal(boolean isEnabled,
-            String whitelist, Collection<String> packageNamesInSameProcess) {
-        if (!isEnabled) {
-            return false;
-        }
-
-        if ("ALL".equals(whitelist)) {
-            return true;
-        }
-        for (String oobPkgName : whitelist.split(",")) {
-            if (packageNamesInSameProcess.contains(oobPkgName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
      * Generates log if the archive located at {@code fileName} has uncompressed dex file that can
      * be direclty mapped.
      */
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/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index e0d5aec..6caddaf 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -34,6 +34,7 @@
 import android.util.Slog;
 
 import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.pm.PackageManagerException;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.parsing.pkg.PackageImpl;
@@ -151,6 +152,12 @@
     @AnyThread
     public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches,
             List<File> frameworkSplits) throws PackageManagerException {
+        var files = packageFile.listFiles();
+        // Apk directory is directly nested under the current directory
+        if (ArrayUtils.size(files) == 1 && files[0].isDirectory()) {
+            packageFile = files[0];
+        }
+
         if (useCaches && mCacher != null) {
             ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
             if (parsed != null) {
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 33b32f8..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<>();
@@ -545,6 +546,9 @@
         for (int i = component.getIntents().size() - 1; i >= 0; i--) {
             IntentFilter filter = component.getIntents().get(i).getIntentFilter();
             for (int groupIndex = filter.countMimeGroups() - 1; groupIndex >= 0; groupIndex--) {
+                if (mimeGroups != null && mimeGroups.size() > 500) {
+                    throw new IllegalStateException("Max limit on number of MIME Groups reached");
+                }
                 mimeGroups = ArrayUtils.add(mimeGroups, filter.getMimeGroup(groupIndex));
             }
         }
@@ -2588,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 164445c..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;
@@ -2692,7 +2691,6 @@
                     final Permission bp = mRegistry.getPermission(permName);
                     final boolean appSupportsRuntimePermissions =
                             pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
-                    String legacyActivityRecognitionPermission = null;
 
                     if (DEBUG_INSTALL && bp != null) {
                         Log.i(TAG, "Package " + friendlyName
@@ -2716,47 +2714,12 @@
                     // Cache newImplicitPermissions before modifing permissionsState as for the
                     // shared uids the original and new state are the same object
                     if (!origState.hasPermissionState(permName)
-                            && (pkg.getImplicitPermissions().contains(permName)
-                            || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
-                        if (pkg.getImplicitPermissions().contains(permName)) {
+                            && (pkg.getImplicitPermissions().contains(permName))) {
                             // If permName is an implicit permission, try to auto-grant
                             newImplicitPermissions.add(permName);
-
                             if (DEBUG_PERMISSIONS) {
                                 Slog.i(TAG, permName + " is newly added for " + friendlyName);
                             }
-                        } else {
-                            // Special case for Activity Recognition permission. Even if AR
-                            // permission is not an implicit permission we want to add it to the
-                            // list (try to auto-grant it) if the app was installed on a device
-                            // before AR permission was split, regardless of if the app now requests
-                            // the new AR permission or has updated its target SDK and AR is no
-                            // longer implicit to it. This is a compatibility workaround for apps
-                            // when AR permission was split in Q.
-                            // TODO(zhanghai): This calls into SystemConfig, which generally
-                            //  shouldn't  cause deadlock, but maybe we should keep a cache of the
-                            //  split permission  list and just eliminate the possibility.
-                            final List<PermissionManager.SplitPermissionInfo> permissionList =
-                                    getSplitPermissionInfos();
-                            int numSplitPerms = permissionList.size();
-                            for (int splitPermNum = 0; splitPermNum < numSplitPerms;
-                                    splitPermNum++) {
-                                PermissionManager.SplitPermissionInfo sp = permissionList.get(
-                                        splitPermNum);
-                                String splitPermName = sp.getSplitPermission();
-                                if (sp.getNewPermissions().contains(permName)
-                                        && origState.isPermissionGranted(splitPermName)) {
-                                    legacyActivityRecognitionPermission = splitPermName;
-                                    newImplicitPermissions.add(permName);
-
-                                    if (DEBUG_PERMISSIONS) {
-                                        Slog.i(TAG, permName + " is newly added for "
-                                                + friendlyName);
-                                    }
-                                    break;
-                                }
-                            }
-                        }
                     }
 
                     // TODO(b/140256621): The package instant app method has been removed
@@ -2890,8 +2853,7 @@
                             // Hard restricted permissions cannot be held.
                             } else if (!permissionPolicyInitialized
                                     || (!hardRestricted || restrictionExempt)) {
-                                if ((origPermState != null && origPermState.isGranted())
-                                        || legacyActivityRecognitionPermission != null) {
+                                if ((origPermState != null && origPermState.isGranted())) {
                                     if (!uidState.grantPermission(bp)) {
                                         wasChanged = true;
                                     }
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 []\[email protected](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 []\[email protected](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/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 9213c87..9dfaca8 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -106,16 +106,43 @@
             return KeyEvent.keyCodeToString(mKeyCode1) + " + "
                     + KeyEvent.keyCodeToString(mKeyCode2);
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o instanceof TwoKeysCombinationRule) {
+                TwoKeysCombinationRule that = (TwoKeysCombinationRule) o;
+                return (mKeyCode1 == that.mKeyCode1 && mKeyCode2 == that.mKeyCode2) || (
+                        mKeyCode1 == that.mKeyCode2 && mKeyCode2 == that.mKeyCode1);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mKeyCode1;
+            result = 31 * result + mKeyCode2;
+            return result;
+        }
     }
 
-    public KeyCombinationManager(Handler handler) {
+    KeyCombinationManager(Handler handler) {
         mHandler = handler;
     }
 
     void addRule(TwoKeysCombinationRule rule) {
+        if (mRules.contains(rule)) {
+            throw new IllegalArgumentException("Rule : " + rule + " already exists.");
+        }
         mRules.add(rule);
     }
 
+    void removeRule(TwoKeysCombinationRule rule) {
+        mRules.remove(rule);
+    }
+
     /**
      * Check if the key event could be intercepted by combination key rule before it is dispatched
      * to a window.
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 1a1de03..e332ac7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -185,6 +185,7 @@
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
 import com.android.internal.accessibility.util.AccessibilityUtils;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.AssistUtils;
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.logging.MetricsLogger;
@@ -224,6 +225,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * WindowManagerPolicy implementation for the Android phone UI.  This
@@ -437,6 +439,7 @@
         }
     };
 
+    private Supplier<GlobalActions> mGlobalActionsFactory;
     private GlobalActions mGlobalActions;
     private Handler mHandler;
 
@@ -914,7 +917,8 @@
             }
         } else {
             // handled by another power key policy.
-            if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
+            if (mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
+                Slog.d(TAG, "Skip power key gesture for other policy has handled it.");
                 mSingleKeyGestureDetector.reset();
             }
         }
@@ -928,11 +932,6 @@
                 // Abort possibly stuck animations only when power key up without long press case.
                 mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
             }
-        } else {
-            // handled by single key or another power key policy.
-            if (!mSingleKeyGestureDetector.isKeyIntercepted(KEYCODE_POWER)) {
-                mSingleKeyGestureDetector.reset();
-            }
         }
 
         finishPowerKeyPress();
@@ -1544,7 +1543,7 @@
 
     void showGlobalActionsInternal() {
         if (mGlobalActions == null) {
-            mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
+            mGlobalActions = mGlobalActionsFactory.get();
         }
         final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
         mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
@@ -1868,11 +1867,45 @@
         mDefaultDisplayPolicy = mDefaultDisplayRotation.getDisplayPolicy();
     }
 
+    /** Point of injection for test dependencies. */
+    @VisibleForTesting
+    static class Injector {
+        private final Context mContext;
+        private final WindowManagerFuncs mWindowManagerFuncs;
+
+        Injector(Context context, WindowManagerFuncs funcs) {
+            mContext = context;
+            mWindowManagerFuncs = funcs;
+        }
+
+        Context getContext() {
+            return mContext;
+        }
+
+        WindowManagerFuncs getWindowManagerFuncs() {
+            return mWindowManagerFuncs;
+        }
+
+        AccessibilityShortcutController getAccessibilityShortcutController(
+                Context context, Handler handler, int initialUserId) {
+            return new AccessibilityShortcutController(context, handler, initialUserId);
+        }
+
+        Supplier<GlobalActions> getGlobalActionsFactory() {
+            return () -> new GlobalActions(mContext, mWindowManagerFuncs);
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
-    public void init(Context context, WindowManagerFuncs windowManagerFuncs) {
-        mContext = context;
-        mWindowManagerFuncs = windowManagerFuncs;
+    public void init(Context context, WindowManagerFuncs funcs) {
+        init(new Injector(context, funcs));
+    }
+
+    @VisibleForTesting
+    void init(Injector injector) {
+        mContext = injector.getContext();
+        mWindowManagerFuncs = injector.getWindowManagerFuncs();
         mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
@@ -1887,8 +1920,9 @@
         mHasFeatureLeanback = mPackageManager.hasSystemFeature(FEATURE_LEANBACK);
         mHasFeatureAuto = mPackageManager.hasSystemFeature(FEATURE_AUTOMOTIVE);
         mHasFeatureHdmiCec = mPackageManager.hasSystemFeature(FEATURE_HDMI_CEC);
-        mAccessibilityShortcutController =
-                new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
+        mAccessibilityShortcutController = injector.getAccessibilityShortcutController(
+                mContext, new Handler(), mCurrentUserId);
+        mGlobalActionsFactory = injector.getGlobalActionsFactory();
         mLogger = new MetricsLogger();
 
         mScreenOffSleepTokenAcquirer = mActivityTaskManagerInternal
@@ -1903,7 +1937,7 @@
                 res.getBoolean(com.android.internal.R.bool.config_wakeOnBackKeyPress);
 
         // Init display burn-in protection
-        boolean burnInProtectionEnabled = context.getResources().getBoolean(
+        boolean burnInProtectionEnabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableBurnInProtection);
         // Allow a system property to override this. Used by developer settings.
         boolean burnInProtectionDevMode =
@@ -1921,7 +1955,7 @@
                 maxVertical = -4;
                 maxRadius = (isRoundWindow()) ? 6 : -1;
             } else {
-                Resources resources = context.getResources();
+                Resources resources = mContext.getResources();
                 minHorizontal = resources.getInteger(
                         com.android.internal.R.integer.config_burnInProtectionMinHorizontalOffset);
                 maxHorizontal = resources.getInteger(
@@ -1934,21 +1968,21 @@
                         com.android.internal.R.integer.config_burnInProtectionMaxRadius);
             }
             mBurnInProtectionHelper = new BurnInProtectionHelper(
-                    context, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius);
+                    mContext, minHorizontal, maxHorizontal, minVertical, maxVertical, maxRadius);
         }
 
         mHandler = new PolicyHandler();
         mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
-        mModifierShortcutManager = new ModifierShortcutManager(context);
-        mUiMode = context.getResources().getInteger(
+        mModifierShortcutManager = new ModifierShortcutManager(mContext);
+        mUiMode = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultUiModeType);
         mHomeIntent =  new Intent(Intent.ACTION_MAIN, null);
         mHomeIntent.addCategory(Intent.CATEGORY_HOME);
         mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-        mEnableCarDockHomeCapture = context.getResources().getBoolean(
+        mEnableCarDockHomeCapture = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableCarDockHomeLaunch);
         mCarDockIntent =  new Intent(Intent.ACTION_MAIN, null);
         mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
@@ -1963,7 +1997,7 @@
         mVrHeadsetHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
 
-        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBroadcastWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                 "PhoneWindowManager.mBroadcastWakeLock");
         mPowerKeyWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
@@ -2035,9 +2069,9 @@
 
         readConfigurationDependentBehaviors();
 
-        mDisplayFoldController = DisplayFoldController.create(context, DEFAULT_DISPLAY);
+        mDisplayFoldController = DisplayFoldController.create(mContext, DEFAULT_DISPLAY);
 
-        mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+        mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
 
         // register for dock events
@@ -2047,7 +2081,7 @@
         filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE);
         filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE);
         filter.addAction(Intent.ACTION_DOCK_EVENT);
-        Intent intent = context.registerReceiver(mDockReceiver, filter);
+        Intent intent = mContext.registerReceiver(mDockReceiver, filter);
         if (intent != null) {
             // Retrieve current sticky dock event broadcast.
             mDefaultDisplayPolicy.setDockMode(intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
@@ -2058,13 +2092,13 @@
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_DREAMING_STARTED);
         filter.addAction(Intent.ACTION_DREAMING_STOPPED);
-        context.registerReceiver(mDreamReceiver, filter);
+        mContext.registerReceiver(mDreamReceiver, filter);
 
         // register for multiuser-relevant broadcasts
         filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        context.registerReceiver(mMultiuserReceiver, filter);
+        mContext.registerReceiver(mMultiuserReceiver, filter);
 
-        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+        mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
                 com.android.internal.R.array.config_safeModeEnabledVibePattern);
 
@@ -2896,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:
diff --git a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
index f00edf3..92f00113 100644
--- a/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
+++ b/services/core/java/com/android/server/policy/SingleKeyGestureDetector.java
@@ -151,6 +151,23 @@
                     + ", VeryLongPress=" + supportVeryLongPress()
                     + ", MaxMultiPressCount=" + getMaxMultiPressCount();
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o instanceof SingleKeyRule) {
+                SingleKeyRule that = (SingleKeyRule) o;
+                return mKeyCode == that.mKeyCode;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return mKeyCode;
+        }
     }
 
     static SingleKeyGestureDetector get(Context context) {
@@ -167,9 +184,16 @@
     }
 
     void addRule(SingleKeyRule rule) {
+        if (mRules.contains(rule)) {
+            throw new IllegalArgumentException("Rule : " + rule + " already exists.");
+        }
         mRules.add(rule);
     }
 
+    void removeRule(SingleKeyRule rule) {
+        mRules.remove(rule);
+    }
+
     void interceptKey(KeyEvent event, boolean interactive) {
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             // Store the non interactive state when first down.
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/LowPowerStandbyController.java b/services/core/java/com/android/server/power/LowPowerStandbyController.java
index 5964fa4..ebeb1455 100644
--- a/services/core/java/com/android/server/power/LowPowerStandbyController.java
+++ b/services/core/java/com/android/server/power/LowPowerStandbyController.java
@@ -201,6 +201,7 @@
             mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.LOW_POWER_STANDBY_ACTIVE_DURING_MAINTENANCE),
                     false, mSettingsObserver, UserHandle.USER_ALL);
+            initSettingsLocked();
             updateSettingsLocked();
 
             if (mIsEnabled) {
@@ -212,6 +213,23 @@
     }
 
     @GuardedBy("mLock")
+    private void initSettingsLocked() {
+        final ContentResolver resolver = mContext.getContentResolver();
+        if (mSupportedConfig) {
+            final int enabledSetting = Settings.Global.getInt(resolver,
+                    Settings.Global.LOW_POWER_STANDBY_ENABLED, /* def= */ -1);
+
+            // If the ENABLED setting hasn't been assigned yet, set it to its default value.
+            // This ensures reading the setting reflects the enabled state, without having to know
+            // the default value for this device.
+            if (enabledSetting == -1) {
+                Settings.Global.putInt(resolver, Settings.Global.LOW_POWER_STANDBY_ENABLED,
+                        /* value= */ mEnabledByDefaultConfig ? 1 : 0);
+            }
+        }
+    }
+
+    @GuardedBy("mLock")
     private void updateSettingsLocked() {
         final ContentResolver resolver = mContext.getContentResolver();
         mIsEnabled = mSupportedConfig && Settings.Global.getInt(resolver,
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 2a1748c..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();
@@ -2953,7 +2962,8 @@
 
             mHandler.removeMessages(MSG_ATTENTIVE_TIMEOUT);
 
-            if (isBeingKeptFromInattentiveSleepLocked()) {
+            if (getGlobalWakefulnessLocked() == WAKEFULNESS_ASLEEP
+                    || isBeingKeptFromInattentiveSleepLocked()) {
                 return;
             }
 
@@ -2985,7 +2995,7 @@
             return false;
         }
 
-        if (getGlobalWakefulnessLocked() != WAKEFULNESS_AWAKE) {
+        if (getGlobalWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
             mInattentiveSleepWarningOverlayController.dismiss(false);
             return true;
         } else if (attentiveTimeout < 0 || isBeingKeptFromInattentiveSleepLocked()
@@ -4257,7 +4267,7 @@
     void onUserActivity() {
         synchronized (mLock) {
             mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).setLastUserActivityTimeLocked(
-                    mClock.uptimeMillis());
+                    mClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER);
         }
     }
 
@@ -5645,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/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
index df902c2..49ac559 100644
--- a/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/power/stats/BatteryExternalStatsWorker.java
@@ -663,6 +663,11 @@
                     BatteryStats.HistoryItem.EVENT_COLLECT_EXTERNAL_STATS,
                     reason, 0);
 
+            if (measuredEnergyDeltas != null && !measuredEnergyDeltas.isEmpty()) {
+                mStats.recordMeasuredEnergyDetailsLocked(elapsedRealtime, uptime,
+                        mMeasuredEnergySnapshot.getMeasuredEnergyDetails(measuredEnergyDeltas));
+            }
+
             if ((updateFlags & UPDATE_CPU) != 0) {
                 if (useLatestStates) {
                     onBattery = mStats.isOnBatteryLocked();
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 968f916..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);
@@ -7404,6 +7405,16 @@
         return names;
     }
 
+    /**
+     * Adds measured energy delta to battery history.
+     */
+    @GuardedBy("this")
+    public void recordMeasuredEnergyDetailsLocked(long elapsedRealtimeMs,
+            long uptimeMs, MeasuredEnergyDetails measuredEnergyDetails) {
+        mHistory.recordMeasuredEnergyDetails(elapsedRealtimeMs, uptimeMs,
+                measuredEnergyDetails);
+    }
+
     @GuardedBy("this")
     @Override public long getStartClockTime() {
         final long currentTimeMs = mClock.currentTimeMillis();
@@ -8836,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());
             }
         }
@@ -14955,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
      */
@@ -16287,6 +16310,9 @@
         dumpConstantsLocked(pw);
 
         pw.println();
+        dumpCpuPowerBracketsLocked(pw);
+
+        pw.println();
         dumpMeasuredEnergyStatsLocked(pw);
     }
 
diff --git a/services/core/java/com/android/server/power/stats/MeasuredEnergySnapshot.java b/services/core/java/com/android/server/power/stats/MeasuredEnergySnapshot.java
index b55c799..c8b4e36 100644
--- a/services/core/java/com/android/server/power/stats/MeasuredEnergySnapshot.java
+++ b/services/core/java/com/android/server/power/stats/MeasuredEnergySnapshot.java
@@ -23,19 +23,17 @@
 import android.hardware.power.stats.EnergyConsumerAttribution;
 import android.hardware.power.stats.EnergyConsumerResult;
 import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryStats.MeasuredEnergyDetails;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.PrintWriter;
 
 /**
  * Keeps snapshots of data from previously pulled EnergyConsumerResults.
  */
-@VisibleForTesting
 public class MeasuredEnergySnapshot {
     private static final String TAG = "MeasuredEnergySnapshot";
 
@@ -87,6 +85,8 @@
      */
     private final SparseArray<SparseLongArray> mAttributionSnapshots;
 
+    private MeasuredEnergyDetails mMeasuredEnergyDetails;
+
     /**
      * Constructor that initializes to the given id->EnergyConsumer map, indicating which consumers
      * exist and what their details are.
@@ -128,6 +128,28 @@
 
         /** Map of {@link EnergyConsumerType#OTHER} ordinals to their {uid->chargeUC} maps. */
         public @Nullable SparseLongArray[] otherUidChargesUC = null;
+
+        boolean isEmpty() {
+            return bluetoothChargeUC <= 0
+                    && isEmpty(cpuClusterChargeUC)
+                    && isEmpty(displayChargeUC)
+                    && gnssChargeUC <= 0
+                    && mobileRadioChargeUC <= 0
+                    && wifiChargeUC <= 0
+                    && isEmpty(otherTotalChargeUC);
+        }
+
+        private boolean isEmpty(long[] values) {
+            if (values == null) {
+                return true;
+            }
+            for (long value: values) {
+                if (value > 0) {
+                    return false;
+                }
+            }
+            return true;
+        }
     }
 
     /**
@@ -394,4 +416,119 @@
         // since the last snapshot. Round off to the nearest whole long.
         return (deltaEnergyUJ * MILLIVOLTS_PER_VOLT + (avgVoltageMV / 2)) / avgVoltageMV;
     }
+
+    /**
+     * Converts the MeasuredEnergyDeltaData object to MeasuredEnergyDetails, which can
+     * be saved in battery history.
+     */
+    MeasuredEnergyDetails getMeasuredEnergyDetails(
+            MeasuredEnergySnapshot.MeasuredEnergyDeltaData delta) {
+        if (mMeasuredEnergyDetails == null) {
+            mMeasuredEnergyDetails = createMeasuredEnergyDetails();
+        }
+
+        final long[] chargeUC = mMeasuredEnergyDetails.chargeUC;
+        for (int i = 0; i < mMeasuredEnergyDetails.consumers.length; i++) {
+            MeasuredEnergyDetails.EnergyConsumer energyConsumer =
+                    mMeasuredEnergyDetails.consumers[i];
+            switch (energyConsumer.type) {
+                case EnergyConsumerType.BLUETOOTH:
+                    chargeUC[i] = delta.bluetoothChargeUC;
+                    break;
+                case EnergyConsumerType.CPU_CLUSTER:
+                    if (delta.cpuClusterChargeUC != null) {
+                        chargeUC[i] = delta.cpuClusterChargeUC[energyConsumer.ordinal];
+                    } else {
+                        chargeUC[i] = UNAVAILABLE;
+                    }
+                    break;
+                case EnergyConsumerType.DISPLAY:
+                    if (delta.displayChargeUC != null) {
+                        chargeUC[i] = delta.displayChargeUC[energyConsumer.ordinal];
+                    } else {
+                        chargeUC[i] = UNAVAILABLE;
+                    }
+                    break;
+                case EnergyConsumerType.GNSS:
+                    chargeUC[i] = delta.gnssChargeUC;
+                    break;
+                case EnergyConsumerType.MOBILE_RADIO:
+                    chargeUC[i] = delta.mobileRadioChargeUC;
+                    break;
+                case EnergyConsumerType.WIFI:
+                    chargeUC[i] = delta.wifiChargeUC;
+                    break;
+                case EnergyConsumerType.OTHER:
+                    if (delta.otherTotalChargeUC != null) {
+                        chargeUC[i] = delta.otherTotalChargeUC[energyConsumer.ordinal];
+                    } else {
+                        chargeUC[i] = UNAVAILABLE;
+                    }
+                    break;
+                default:
+                    chargeUC[i] = UNAVAILABLE;
+                    break;
+            }
+        }
+        return mMeasuredEnergyDetails;
+    }
+
+    private MeasuredEnergyDetails createMeasuredEnergyDetails() {
+        MeasuredEnergyDetails details = new MeasuredEnergyDetails();
+        details.consumers =
+                new MeasuredEnergyDetails.EnergyConsumer[mEnergyConsumers.size()];
+        for (int i = 0; i < mEnergyConsumers.size(); i++) {
+            EnergyConsumer energyConsumer = mEnergyConsumers.valueAt(i);
+            MeasuredEnergyDetails.EnergyConsumer consumer =
+                    new MeasuredEnergyDetails.EnergyConsumer();
+            consumer.type = energyConsumer.type;
+            consumer.ordinal = energyConsumer.ordinal;
+            switch (consumer.type) {
+                case EnergyConsumerType.BLUETOOTH:
+                    consumer.name = "BLUETOOTH";
+                    break;
+                case EnergyConsumerType.CPU_CLUSTER:
+                    consumer.name = "CPU";
+                    break;
+                case EnergyConsumerType.DISPLAY:
+                    consumer.name = "DISPLAY";
+                    break;
+                case EnergyConsumerType.GNSS:
+                    consumer.name = "GNSS";
+                    break;
+                case EnergyConsumerType.MOBILE_RADIO:
+                    consumer.name = "MOBILE_RADIO";
+                    break;
+                case EnergyConsumerType.WIFI:
+                    consumer.name = "WIFI";
+                    break;
+                case EnergyConsumerType.OTHER:
+                    consumer.name = sanitizeCustomBucketName(energyConsumer.name);
+                    break;
+                default:
+                    consumer.name = "UNKNOWN";
+                    break;
+            }
+            if (consumer.type != EnergyConsumerType.OTHER) {
+                boolean hasOrdinal = consumer.ordinal != 0;
+                if (!hasOrdinal) {
+                    // See if any other EnergyConsumer of the same type has an ordinal
+                    for (int j = 0; j < mEnergyConsumers.size(); j++) {
+                        EnergyConsumer aConsumer = mEnergyConsumers.valueAt(j);
+                        if (aConsumer.type == consumer.type && aConsumer.ordinal != 0) {
+                            hasOrdinal = true;
+                            break;
+                        }
+                    }
+                }
+                if (hasOrdinal) {
+                    consumer.name = consumer.name + "/" + energyConsumer.ordinal;
+                }
+            }
+            details.consumers[i] = consumer;
+        }
+
+        details.chargeUC = new long[details.consumers.length];
+        return details;
+    }
 }
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/SoundTriggerMiddlewareValidation.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
index 09035cd..15c9ba9 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewareValidation.java
@@ -37,6 +37,7 @@
 import android.os.RemoteException;
 import android.os.ServiceSpecificException;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.internal.util.Preconditions;
 
@@ -829,17 +830,41 @@
             @Override
             public void binderDied() {
                 // This is called whenever our client process dies.
+                SparseArray<ModelState.Activity> cachedMap =
+                        new SparseArray<ModelState.Activity>();
                 synchronized (SoundTriggerMiddlewareValidation.this) {
-                    try {
-                        // Gracefully stop all active recognitions and unload the models.
+                        // Copy the relevant state under the lock, so we can call back without
+                        // holding a lock. This exposes us to a potential race, but the client is
+                        // dead so we don't expect one.
+                        // TODO(240613068) A more resilient fix for this.
                         for (Map.Entry<Integer, ModelState> entry :
                                 mLoadedModels.entrySet()) {
-                            if (entry.getValue().activityState == ModelState.Activity.ACTIVE) {
-                                mDelegate.stopRecognition(entry.getKey());
-                            }
-                            mDelegate.unloadModel(entry.getKey());
+                            cachedMap.put(entry.getKey(), entry.getValue().activityState);
                         }
-                        // Detach.
+                }
+                try {
+                    // Gracefully stop all active recognitions and unload the models.
+                    for (int i = 0; i < cachedMap.size(); i++) {
+                        if (cachedMap.valueAt(i) == ModelState.Activity.ACTIVE) {
+                            mDelegate.stopRecognition(cachedMap.keyAt(i));
+                        }
+                        mDelegate.unloadModel(cachedMap.keyAt(i));
+                    }
+                } catch (Exception e) {
+                    throw handleException(e);
+                }
+                synchronized (SoundTriggerMiddlewareValidation.this) {
+                   // Check if state updated unexpectedly to log race conditions.
+                    for (Map.Entry<Integer, ModelState> entry : mLoadedModels.entrySet()) {
+                        if (cachedMap.get(entry.getKey()) != entry.getValue().activityState) {
+                            Log.e(TAG, "Unexpected state update in binderDied. Race occurred!");
+                        }
+                    }
+                    if (mLoadedModels.size() != cachedMap.size()) {
+                        Log.e(TAG, "Unexpected state update in binderDied. Race occurred!");
+                    }
+                    try {
+                        // Detach
                         detachInternal();
                     } catch (Exception e) {
                         throw handleException(e);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 53b8b53..690dd10 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -21,7 +21,6 @@
 import android.hardware.fingerprint.IUdfpsHbmListener;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.InsetsVisibilities;
 import android.view.WindowInsetsController.Appearance;
@@ -162,11 +161,6 @@
     boolean requestWindowMagnificationConnection(boolean request);
 
     /**
-     * Handles a logging command from the WM shell command.
-     */
-    void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd);
-
-    /**
      * @see com.android.internal.statusbar.IStatusBar#setNavigationBarLumaSamplingEnabled(int,
      * boolean)
      */
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index bec3754..653b51a9 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -62,7 +62,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -664,15 +663,6 @@
         }
 
         @Override
-        public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
-            if (mBar != null) {
-                try {
-                    mBar.handleWindowManagerLoggingCommand(args, outFd);
-                } catch (RemoteException ex) { }
-            }
-        }
-
-        @Override
         public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
             if (mBar != null) {
                 try {
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/vibrator/StartSequentialEffectStep.java b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
index 2c6fbbc9..fd1a3ac 100644
--- a/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
+++ b/services/core/java/com/android/server/vibrator/StartSequentialEffectStep.java
@@ -192,41 +192,44 @@
         // delivered asynchronously but enqueued until the step processing is finished.
         boolean hasPrepared = false;
         boolean hasTriggered = false;
+        boolean hasFailed = false;
         long maxDuration = 0;
-        try {
-            hasPrepared = conductor.vibratorManagerHooks.prepareSyncedVibration(
-                    effectMapping.getRequiredSyncCapabilities(),
-                    effectMapping.getVibratorIds());
+        hasPrepared = conductor.vibratorManagerHooks.prepareSyncedVibration(
+                effectMapping.getRequiredSyncCapabilities(),
+                effectMapping.getVibratorIds());
 
-            for (AbstractVibratorStep step : steps) {
-                long duration = startVibrating(step, nextSteps);
-                if (duration < 0) {
-                    // One vibrator has failed, fail this entire sync attempt.
-                    return maxDuration = -1;
-                }
-                maxDuration = Math.max(maxDuration, duration);
+        for (AbstractVibratorStep step : steps) {
+            long duration = startVibrating(step, nextSteps);
+            if (duration < 0) {
+                // One vibrator has failed, fail this entire sync attempt.
+                hasFailed = true;
+                break;
             }
+            maxDuration = Math.max(maxDuration, duration);
+        }
 
-            // Check if sync was prepared and if any step was accepted by a vibrator,
-            // otherwise there is nothing to trigger here.
-            if (hasPrepared && maxDuration > 0) {
-                hasTriggered = conductor.vibratorManagerHooks.triggerSyncedVibration(
-                        getVibration().id);
-            }
-            return maxDuration;
-        } finally {
-            if (hasPrepared && !hasTriggered) {
-                // Trigger has failed or all steps were ignored by the vibrators.
-                conductor.vibratorManagerHooks.cancelSyncedVibration();
-                nextSteps.clear();
-            } else if (maxDuration < 0) {
-                // Some vibrator failed without being prepared so other vibrators might be
-                // active. Cancel and remove every pending step from output list.
-                for (int i = nextSteps.size() - 1; i >= 0; i--) {
-                    nextSteps.remove(i).cancelImmediately();
-                }
+        // Check if sync was prepared and if any step was accepted by a vibrator,
+        // otherwise there is nothing to trigger here.
+        if (hasPrepared && !hasFailed && maxDuration > 0) {
+            hasTriggered = conductor.vibratorManagerHooks.triggerSyncedVibration(getVibration().id);
+            hasFailed &= hasTriggered;
+        }
+
+        if (hasFailed) {
+            // Something failed, possibly after other vibrators were activated.
+            // Cancel and remove every pending step from output list.
+            for (int i = nextSteps.size() - 1; i >= 0; i--) {
+                nextSteps.remove(i).cancelImmediately();
             }
         }
+
+        // Cancel the preparation if trigger failed or all
+        if (hasPrepared && !hasTriggered) {
+            // Trigger has failed or was skipped, so abort the synced vibration.
+            conductor.vibratorManagerHooks.cancelSyncedVibration();
+        }
+
+        return hasFailed ? -1 : maxDuration;
     }
 
     private long startVibrating(AbstractVibratorStep step, List<Step> nextSteps) {
diff --git a/services/core/java/com/android/server/vibrator/Vibration.java b/services/core/java/com/android/server/vibrator/Vibration.java
index 83caa0e..a451ee2 100644
--- a/services/core/java/com/android/server/vibrator/Vibration.java
+++ b/services/core/java/com/android/server/vibrator/Vibration.java
@@ -251,6 +251,20 @@
                 uid, vibrationType, attrs.getUsage(), mStatus, mStats, completionUptimeMillis);
     }
 
+    /**
+     * Returns true if this vibration can pipeline with the specified one.
+     *
+     * <p>Note that currently, repeating vibrations can't pipeline with following vibrations,
+     * because the cancel() call to stop the repetition will cancel a pending vibration too. This
+     * can be changed if we have a use-case to reason around behavior for. It may also be nice to
+     * pipeline very short vibrations together, regardless of the flag.
+     */
+    public boolean canPipelineWith(Vibration vib) {
+        return uid == vib.uid && attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT)
+                && vib.attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT)
+                && !isRepeating();
+    }
+
     /** Immutable info passed as a signal to end a vibration. */
     static final class EndInfo {
         /** The {@link Status} to be set to the vibration when it ends with this info. */
diff --git a/services/core/java/com/android/server/vibrator/VibrationSettings.java b/services/core/java/com/android/server/vibrator/VibrationSettings.java
index d7bfd1d..fcf0a90 100644
--- a/services/core/java/com/android/server/vibrator/VibrationSettings.java
+++ b/services/core/java/com/android/server/vibrator/VibrationSettings.java
@@ -263,8 +263,10 @@
                     }
                 });
 
-        vdm.registerVirtualDisplayListener(mVirtualDeviceListener);
-        vdm.registerAppsOnVirtualDeviceListener(mVirtualDeviceListener);
+        if (vdm != null){
+          vdm.registerVirtualDisplayListener(mVirtualDeviceListener);
+          vdm.registerAppsOnVirtualDeviceListener(mVirtualDeviceListener);
+        }
 
         registerSettingsChangeReceiver(USER_SWITCHED_INTENT_FILTER);
         registerSettingsChangeReceiver(INTERNAL_RINGER_MODE_CHANGED_INTENT_FILTER);
diff --git a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
index 0af1718..8ac4fd4 100644
--- a/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
+++ b/services/core/java/com/android/server/vibrator/VibrationStepConductor.java
@@ -281,6 +281,14 @@
         // to run it before processing callbacks as the window is tiny.
         Step nextStep = pollNext();
         if (nextStep != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Playing vibration id " + getVibration().id
+                        + ((nextStep instanceof AbstractVibratorStep)
+                        ? " on vibrator " + ((AbstractVibratorStep) nextStep).getVibratorId() : "")
+                        + " " + nextStep.getClass().getSimpleName()
+                        + (nextStep.isCleanUp() ? " (cleanup)" : ""));
+            }
+
             List<Step> nextSteps = nextStep.play();
             if (nextStep.getVibratorOnDuration() > 0) {
                 mSuccessfulVibratorOnSteps++;
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index e824db10..3fd9594 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -292,9 +292,6 @@
                 boolean readyToRun = mExecutingConductor.waitUntilNextStepIsDue();
                 // If we waited, don't run the next step, but instead re-evaluate status.
                 if (readyToRun) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "Play vibration consuming next step...");
-                    }
                     // Run the step without holding the main lock, to avoid HAL interactions from
                     // blocking the thread.
                     mExecutingConductor.runNextStep();
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index 0159572..8514e27 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -419,7 +419,7 @@
 
             synchronized (mLock) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Starting vibrate for vibration  " + vib.id);
+                    Slog.d(TAG, "Starting vibrate for vibration " + vib.id);
                 }
                 int ignoredByUid = -1;
                 int ignoredByUsage = -1;
@@ -450,13 +450,23 @@
                     final long ident = Binder.clearCallingIdentity();
                     try {
                         if (mCurrentVibration != null) {
-                            vib.stats().reportInterruptedAnotherVibration(
-                                    mCurrentVibration.getVibration().attrs.getUsage());
-                            mCurrentVibration.notifyCancelled(
-                                    new Vibration.EndInfo(
-                                            Vibration.Status.CANCELLED_SUPERSEDED, vib.uid,
-                                            vib.attrs.getUsage()),
-                                    /* immediate= */ false);
+                            if (mCurrentVibration.getVibration().canPipelineWith(vib)) {
+                                // Don't cancel the current vibration if it's pipeline-able.
+                                // Note that if there is a pending next vibration that can't be
+                                // pipelined, it will have already cancelled the current one, so we
+                                // don't need to consider it here as well.
+                                if (DEBUG) {
+                                    Slog.d(TAG, "Pipelining vibration " + vib.id);
+                                }
+                            } else {
+                                vib.stats().reportInterruptedAnotherVibration(
+                                        mCurrentVibration.getVibration().attrs.getUsage());
+                                mCurrentVibration.notifyCancelled(
+                                        new Vibration.EndInfo(
+                                                Vibration.Status.CANCELLED_SUPERSEDED, vib.uid,
+                                                vib.attrs.getUsage()),
+                                        /* immediate= */ false);
+                            }
                         }
                         status = startVibrationLocked(vib);
                     } finally {
@@ -690,6 +700,8 @@
             }
             // If there's already a vibration queued (waiting for the previous one to finish
             // cancelling), end it cleanly and replace it with the new one.
+            // Note that we don't consider pipelining here, because new pipelined ones should
+            // replace pending non-executing pipelined ones anyway.
             clearNextVibrationLocked(
                     new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED,
                             vib.uid, vib.attrs.getUsage()));
@@ -1594,6 +1606,10 @@
     @GuardedBy("mLock")
     private void clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo) {
         if (mNextVibration != null) {
+            if (DEBUG) {
+                Slog.d(TAG, "Dropping pending vibration " + mNextVibration.getVibration().id
+                        + " with end info: " + vibrationEndInfo);
+            }
             // Clearing next vibration before playing it, end it and report metrics right away.
             endVibrationLocked(mNextVibration.getVibration(), vibrationEndInfo,
                     /* shouldWriteStats= */ true);
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/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index c04b195..804689a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -422,7 +422,7 @@
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
             mAccessibilityTracing.logTrace(TAG + ".onSomeWindowResizedOrMoved",
                     FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK,
-                    "displayIds={" + displayIds.toString() + "}", "".getBytes(), callingUid);
+                    "displayIds={" + Arrays.toString(displayIds) + "}", "".getBytes(), callingUid);
         }
         // Not relevant for the display magnifier.
         for (int i = 0; i < displayIds.length; i++) {
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 f8f94f6..16b5ee5 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -79,6 +79,7 @@
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO;
+import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_MEDIUM;
 import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY;
@@ -356,7 +357,6 @@
 import com.android.server.wm.SurfaceAnimator.AnimationType;
 import com.android.server.wm.WindowManagerService.H;
 import com.android.server.wm.utils.InsetUtils;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import dalvik.annotation.optimization.NeverCompile;
 
@@ -916,7 +916,6 @@
      */
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
-    private final Rect mTmpOutNonDecorBounds = new Rect();
 
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
@@ -1582,13 +1581,6 @@
 
         if (newParent != null && isState(RESUMED)) {
             newParent.setResumedActivity(this, "onParentChanged");
-            if (mStartingWindow != null && mStartingData != null
-                    && mStartingData.mAssociatedTask == null && newParent.isEmbedded()) {
-                // The starting window should keep covering its task when the activity is
-                // reparented to a task fragment that may not fill the task bounds.
-                associateStartingDataWithTask();
-                attachStartingSurfaceToAssociatedTask();
-            }
             mImeInsetsFrozenUntilStartInput = false;
         }
 
@@ -2128,7 +2120,7 @@
 
         mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
 
-        updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
+        updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
     }
 
     /**
@@ -2679,14 +2671,17 @@
         }
     }
 
+    /** Called when the starting window is added to this activity. */
     void attachStartingWindow(@NonNull WindowState startingWindow) {
         startingWindow.mStartingData = mStartingData;
         mStartingWindow = startingWindow;
+        // The snapshot type may have called associateStartingDataWithTask().
         if (mStartingData != null && mStartingData.mAssociatedTask != null) {
             attachStartingSurfaceToAssociatedTask();
         }
     }
 
+    /** Makes starting window always fill the associated task. */
     private void attachStartingSurfaceToAssociatedTask() {
         // Associate the configuration of starting window with the task.
         overrideConfigurationPropagation(mStartingWindow, mStartingData.mAssociatedTask);
@@ -2694,6 +2689,7 @@
                 mStartingData.mAssociatedTask.mSurfaceControl);
     }
 
+    /** Called when the starting window is not added yet but its data is known to fill the task. */
     private void associateStartingDataWithTask() {
         mStartingData.mAssociatedTask = task;
         task.forAllActivities(r -> {
@@ -2703,6 +2699,16 @@
         });
     }
 
+    /** Associates and attaches an added starting window to the current task. */
+    void associateStartingWindowWithTaskIfNeeded() {
+        if (mStartingWindow == null || mStartingData == null
+                || mStartingData.mAssociatedTask != null) {
+            return;
+        }
+        associateStartingDataWithTask();
+        attachStartingSurfaceToAssociatedTask();
+    }
+
     void removeStartingWindow() {
         boolean prevEligibleForLetterboxEducation = isEligibleForLetterboxEducation();
 
@@ -7418,7 +7424,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);
@@ -8135,10 +8141,12 @@
         final int orientation = parentBounds.height() >= parentBounds.width()
                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
         // Compute orientation from stable parent bounds (= parent bounds with insets applied)
+        final DisplayInfo di = isFixedRotationTransforming()
+                ? getFixedRotationTransformDisplayInfo()
+                : mDisplayContent.getDisplayInfo();
         final Task task = getTask();
-        task.calculateInsetFrames(mTmpOutNonDecorBounds /* outNonDecorBounds */,
-                outStableBounds /* outStableBounds */, parentBounds /* bounds */,
-                mDisplayContent.getDisplayInfo());
+        task.calculateInsetFrames(mTmpBounds /* outNonDecorBounds */,
+                outStableBounds /* outStableBounds */, parentBounds /* bounds */, di);
         final int orientationWithInsets = outStableBounds.height() >= outStableBounds.width()
                 ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
         // If orientation does not match the orientation with insets applied, then a
@@ -8802,9 +8810,25 @@
      * Returns the min aspect ratio of this activity.
      */
     float getMinAspectRatio() {
-        if (info.applicationInfo == null || !info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO) || (
-                info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
-                        && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation()))) {
+        if (info.applicationInfo == null) {
+            return info.getMinAspectRatio();
+        }
+
+        if (!info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO)) {
+            return info.getMinAspectRatio();
+        }
+
+        if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_ONLY)
+                && !ActivityInfo.isFixedOrientationPortrait(getRequestedOrientation())) {
+            return info.getMinAspectRatio();
+        }
+
+        if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
+                && getParent().getConfiguration().orientation == ORIENTATION_PORTRAIT
+                && getParent().getWindowConfiguration().getWindowingMode()
+                        == WINDOWING_MODE_FULLSCREEN) {
+            // We are using the parent configuration here as this is the most recent one that gets
+            // passed to onConfigurationChanged when a relevant change takes place
             return info.getMinAspectRatio();
         }
 
@@ -9684,10 +9708,10 @@
                 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
                 final int dw = rotated ? display.mBaseDisplayHeight : display.mBaseDisplayWidth;
                 final int dh = rotated ? display.mBaseDisplayWidth : display.mBaseDisplayHeight;
-                final WmDisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation);
-                policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]);
-                mStableInsets[rotation].set(mNonDecorInsets[rotation]);
-                policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation);
+                final DisplayPolicy.DecorInsets.Info decorInfo =
+                        policy.getDecorInsetsInfo(rotation, dw, dh);
+                mNonDecorInsets[rotation].set(decorInfo.mNonDecorInsets);
+                mStableInsets[rotation].set(decorInfo.mConfigInsets);
 
                 if (unfilledContainerBounds == null) {
                     continue;
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 8f18064..d131457 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -97,6 +97,8 @@
     /** Whether an {@link ActivityStarter} is currently executing (starting an Activity). */
     private boolean mInExecution = false;
 
+    private final BackgroundActivityStartController mBalController;
+
     /**
      * TODO(b/64750076): Capture information necessary for dump and
      * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object
@@ -119,6 +121,7 @@
         mFactory.setController(this);
         mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock,
                 service.mH);
+        mBalController = new BackgroundActivityStartController(mService, mSupervisor);
     }
 
     /**
@@ -384,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];
@@ -432,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)
@@ -632,4 +643,8 @@
             pw.println("(nothing)");
         }
     }
+
+    BackgroundActivityStartController getBackgroundActivityLaunchController() {
+        return mBalController;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 619d693..bc1c6b2 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.Activity.RESULT_CANCELED;
 import static android.app.ActivityManager.START_ABORTED;
 import static android.app.ActivityManager.START_CANCELED;
@@ -52,7 +51,6 @@
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.launchModeToString;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.os.Process.INVALID_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_OPEN;
@@ -61,7 +59,6 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
@@ -72,8 +69,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
-import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
@@ -98,7 +93,6 @@
 import android.app.WindowConfiguration;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
-import android.content.ComponentName;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -114,15 +108,12 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.DebugUtils;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
 import android.window.RemoteTransition;
@@ -203,6 +194,10 @@
     private TaskFragment mAddingToTaskFragment;
     @VisibleForTesting
     boolean mAddingToTask;
+    // Activity that was moved to the top of its task in situations where activity-order changes
+    // due to launch flags (eg. REORDER_TO_TOP).
+    @VisibleForTesting
+    ActivityRecord mMovedToTopActivity;
 
     private Task mSourceRootTask;
     private Task mTargetRootTask;
@@ -259,8 +254,6 @@
 
         /**
          * Generates an {@link ActivityStarter} that is ready to handle a new start request.
-         * @param controller The {@link ActivityStartController} which the starter who will own
-         *                   this instance.
          * @return an {@link ActivityStarter}
          */
         ActivityStarter obtain();
@@ -1033,10 +1026,20 @@
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
                         "shouldAbortBackgroundActivityStart");
-                restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
-                        callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
-                        request.originatingPendingIntent, request.allowBackgroundActivityStart,
-                        intent, checkedOptions);
+                BackgroundActivityStartController balController =
+                        mController.getBackgroundActivityLaunchController();
+                restrictedBgActivity =
+                        balController.shouldAbortBackgroundActivityStart(
+                                callingUid,
+                                callingPid,
+                                callingPackage,
+                                realCallingUid,
+                                realCallingPid,
+                                callerApp,
+                                request.originatingPendingIntent,
+                                request.allowBackgroundActivityStart,
+                                intent,
+                                checkedOptions);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
             }
@@ -1270,282 +1273,6 @@
         mController.onExecutionStarted();
     }
 
-    private boolean isHomeApp(int uid, @Nullable String packageName) {
-        if (mService.mHomeProcess != null) {
-            // Fast check
-            return uid == mService.mHomeProcess.mUid;
-        }
-        if (packageName == null) {
-            return false;
-        }
-        ComponentName activity =
-                mService.getPackageManagerInternalLocked().getDefaultHomeActivity(
-                        UserHandle.getUserId(uid));
-        return activity != null && packageName.equals(activity.getPackageName());
-    }
-
-    boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
-            final String callingPackage, int realCallingUid, int realCallingPid,
-            WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
-            boolean allowBackgroundActivityStart, Intent intent, ActivityOptions checkedOptions) {
-        // don't abort for the most important UIDs
-        final int callingAppId = UserHandle.getAppId(callingUid);
-        final boolean useCallingUidState =
-                originatingPendingIntent == null || checkedOptions == null
-                        || !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
-        if (useCallingUidState) {
-            if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
-                    || callingAppId == Process.NFC_UID) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG,
-                            "Activity start allowed for important callingUid (" + callingUid + ")");
-                }
-                return false;
-            }
-
-            // Always allow home application to start activities.
-            if (isHomeApp(callingUid, callingPackage)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG,
-                            "Activity start allowed for home app callingUid (" + callingUid + ")");
-                }
-                return false;
-            }
-
-            // IME should always be allowed to start activity, like IME settings.
-            final WindowState imeWindow = mRootWindowContainer.getCurrentInputMethodWindow();
-            if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")");
-                }
-                return false;
-            }
-        }
-
-        // This is used to block background activity launch even if the app is still
-        // visible to user after user clicking home button.
-        final int appSwitchState = mService.getBalAppSwitchesState();
-
-        // don't abort if the callingUid has a visible window or is a persistent system process
-        final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
-        final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
-        final boolean isCallingUidForeground = callingUidHasAnyVisibleWindow
-                || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
-                || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
-        final boolean isCallingUidPersistentSystemProcess =
-                callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-
-        // Normal apps with visible app window will be allowed to start activity if app switching
-        // is allowed, or apps like live wallpaper with non app visible window will be allowed.
-        final boolean appSwitchAllowedOrFg =
-                appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
-        final boolean allowCallingUidStartActivity =
-                ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
-                && callingUidHasAnyVisibleWindow)
-                || isCallingUidPersistentSystemProcess;
-        if (useCallingUidState && allowCallingUidStartActivity) {
-            if (DEBUG_ACTIVITY_STARTS) {
-                Slog.d(TAG, "Activity start allowed: callingUidHasAnyVisibleWindow = " + callingUid
-                        + ", isCallingUidPersistentSystemProcess = "
-                        + isCallingUidPersistentSystemProcess);
-            }
-            return false;
-        }
-        // take realCallingUid into consideration
-        final int realCallingUidProcState = (callingUid == realCallingUid)
-                ? callingUidProcState
-                : mService.mActiveUids.getUidState(realCallingUid);
-        final boolean realCallingUidHasAnyVisibleWindow = (callingUid == realCallingUid)
-                ? callingUidHasAnyVisibleWindow
-                : mService.hasActiveVisibleWindow(realCallingUid);
-        final boolean isRealCallingUidForeground = (callingUid == realCallingUid)
-                ? isCallingUidForeground
-                : realCallingUidHasAnyVisibleWindow
-                        || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
-        final int realCallingAppId = UserHandle.getAppId(realCallingUid);
-        final boolean isRealCallingUidPersistentSystemProcess = (callingUid == realCallingUid)
-                ? isCallingUidPersistentSystemProcess
-                : (realCallingAppId == Process.SYSTEM_UID)
-                        || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
-
-        // In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
-        // visible window.
-        if (Process.isSdkSandboxUid(realCallingUid)) {
-            int realCallingSdkSandboxUidToAppUid = Process.getAppUidForSdkSandboxUid(
-                    UserHandle.getAppId(realCallingUid));
-
-            if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: uid in SDK sandbox ("
-                            + realCallingUid + ") has visible (non-toast) window.");
-                }
-                return false;
-            }
-        }
-
-        // Legacy behavior allows to use caller foreground state to bypass BAL restriction.
-        final boolean balAllowedByPiSender =
-                PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
-
-        if (balAllowedByPiSender && realCallingUid != callingUid) {
-            final boolean useCallerPermission =
-                    PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
-            if (useCallerPermission && ActivityManager.checkComponentPermission(
-                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
-                    realCallingUid, -1, true)
-                    == PackageManager.PERMISSION_GRANTED) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") has BAL permission.");
-                }
-                return false;
-            }
-
-            // don't abort if the realCallingUid has a visible window
-            // TODO(b/171459802): We should check appSwitchAllowed also
-            if (realCallingUidHasAnyVisibleWindow) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") has visible (non-toast) window");
-                }
-                return false;
-            }
-            // if the realCallingUid is a persistent system process, abort if the IntentSender
-            // wasn't allowed to start an activity
-            if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") is persistent system process AND intent sender allowed "
-                            + "(allowBackgroundActivityStart = true)");
-                }
-                return false;
-            }
-            // don't abort if the realCallingUid is an associated companion app
-            if (mService.isAssociatedCompanionApp(UserHandle.getUserId(realCallingUid),
-                    realCallingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Activity start allowed: realCallingUid (" + realCallingUid
-                            + ") is companion app");
-                }
-                return false;
-            }
-        }
-        if (useCallingUidState) {
-            // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
-            if (mService.checkPermission(
-                    START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
-                    == PERMISSION_GRANTED) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG,
-                            "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
-                                    + "permission granted for uid "
-                                    + callingUid);
-                }
-                return false;
-            }
-            // don't abort if the caller has the same uid as the recents component
-            if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
-                            + ") is recents");
-                }
-                return false;
-            }
-            // don't abort if the callingUid is the device owner
-            if (mService.isDeviceOwner(callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
-                            + ") is device owner");
-                }
-                return false;
-            }
-            // don't abort if the callingUid has companion device
-            final int callingUserId = UserHandle.getUserId(callingUid);
-            if (mService.isAssociatedCompanionApp(callingUserId,
-                    callingUid)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callingUid (" + callingUid
-                            + ") is companion app");
-                }
-                return false;
-            }
-            // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
-            if (mService.hasSystemAlertWindowPermission(callingUid,
-                    callingPid, callingPackage)) {
-                Slog.w(TAG, "Background activity start for " + callingPackage
-                        + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
-                return false;
-            }
-        }
-        // If we don't have callerApp at this point, no caller was provided to startActivity().
-        // That's the case for PendingIntent-based starts, since the creator's process might not be
-        // up and alive. If that's the case, we retrieve the WindowProcessController for the send()
-        // caller if caller allows, so that we can make the decision based on its state.
-        int callerAppUid = callingUid;
-        if (callerApp == null && balAllowedByPiSender) {
-            callerApp = mService.getProcessController(realCallingPid, realCallingUid);
-            callerAppUid = realCallingUid;
-        }
-        // don't abort if the callerApp or other processes of that uid are allowed in any way
-        if (callerApp != null && useCallingUidState) {
-            // first check the original calling process
-            if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
-                if (DEBUG_ACTIVITY_STARTS) {
-                    Slog.d(TAG, "Background activity start allowed: callerApp process (pid = "
-                            + callerApp.getPid() + ", uid = " + callerAppUid + ") is allowed");
-                }
-                return false;
-            }
-            // only if that one wasn't allowed, check the other ones
-            final ArraySet<WindowProcessController> uidProcesses =
-                    mService.mProcessMap.getProcesses(callerAppUid);
-            if (uidProcesses != null) {
-                for (int i = uidProcesses.size() - 1; i >= 0; i--) {
-                    final WindowProcessController proc = uidProcesses.valueAt(i);
-                    if (proc != callerApp
-                            && proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
-                        if (DEBUG_ACTIVITY_STARTS) {
-                            Slog.d(TAG,
-                                    "Background activity start allowed: process " + proc.getPid()
-                                            + " from uid " + callerAppUid + " is allowed");
-                        }
-                        return false;
-                    }
-                }
-            }
-        }
-        // anything that has fallen through would currently be aborted
-        Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
-                + "; callingUid: " + callingUid
-                + "; appSwitchState: " + appSwitchState
-                + "; isCallingUidForeground: " + isCallingUidForeground
-                + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow
-                + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
-                "PROCESS_STATE_", callingUidProcState)
-                + "; isCallingUidPersistentSystemProcess: " + isCallingUidPersistentSystemProcess
-                + "; realCallingUid: " + realCallingUid
-                + "; isRealCallingUidForeground: " + isRealCallingUidForeground
-                + "; realCallingUidHasAnyVisibleWindow: " + realCallingUidHasAnyVisibleWindow
-                + "; realCallingUidProcState: " + DebugUtils.valueToString(ActivityManager.class,
-                "PROCESS_STATE_", realCallingUidProcState)
-                + "; isRealCallingUidPersistentSystemProcess: "
-                + isRealCallingUidPersistentSystemProcess
-                + "; originatingPendingIntent: " + originatingPendingIntent
-                + "; allowBackgroundActivityStart: " + allowBackgroundActivityStart
-                + "; intent: " + intent
-                + "; callerApp: " + callerApp
-                + "; inVisibleTask: " + (callerApp != null && callerApp.hasActivityInVisibleTask())
-                + "]");
-        // log aborted activity start to TRON
-        if (mService.isActivityStartsLoggingEnabled()) {
-            mSupervisor.getActivityMetricsLogger().logAbortedBgActivityStart(intent, callerApp,
-                    callingUid, callingPackage, callingUidProcState, callingUidHasAnyVisibleWindow,
-                    realCallingUid, realCallingUidProcState, realCallingUidHasAnyVisibleWindow,
-                    (originatingPendingIntent != null));
-        }
-        return true;
-    }
-
     /**
      * Creates a launch intent for the given auxiliary resolution data.
      */
@@ -1761,7 +1488,9 @@
             // The activity is started new rather than just brought forward, so record it as an
             // existence change.
             transitionController.collectExistenceChange(started);
-        } else if (result == START_DELIVERED_TO_TOP && newTransition != null) {
+        } else if (result == START_DELIVERED_TO_TOP && newTransition != null
+                // An activity has changed order/visibility so this isn't just deliver-to-top
+                && mMovedToTopActivity == null) {
             // We just delivered to top, so there isn't an actual transition here.
             if (!forceTransientTransition) {
                 newTransition.abort();
@@ -1866,6 +1595,16 @@
         final ActivityRecord targetTaskTop = newTask
                 ? null : targetTask.getTopNonFinishingActivity();
         if (targetTaskTop != null) {
+            // Removes the existing singleInstance activity in another task (if any) while
+            // launching a singleInstance activity on sourceRecord's task.
+            if (LAUNCH_SINGLE_INSTANCE == mLaunchMode && mSourceRecord != null
+                    && targetTask == mSourceRecord.getTask()) {
+                final ActivityRecord activity = mRootWindowContainer.findActivity(mIntent,
+                        mStartActivity.info, false);
+                if (activity != null && activity.getTask() != targetTask) {
+                    activity.destroyIfPossible("Removes redundant singleInstance");
+                }
+            }
             // Recycle the target task for this launch.
             startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
             if (startResult != START_SUCCESS) {
@@ -2338,10 +2077,15 @@
             // In this situation we want to remove all activities from the task up to the one
             // being started. In most cases this means we are resetting the task to its initial
             // state.
+            int[] finishCount = new int[1];
             final ActivityRecord clearTop = targetTask.performClearTop(mStartActivity,
-                    mLaunchFlags);
+                    mLaunchFlags, finishCount);
 
             if (clearTop != null && !clearTop.finishing) {
+                if (finishCount[0] > 0) {
+                    // Only record if actually moved to top.
+                    mMovedToTopActivity = clearTop;
+                }
                 if (clearTop.isRootOfTask()) {
                     // Activity aliases may mean we use different intents for the top activity,
                     // so make sure the task now has the identity of the new intent.
@@ -2374,10 +2118,15 @@
             // already be running somewhere in the history, and we want to shuffle it to
             // the front of the root task if so.
             final ActivityRecord act =
-                    targetTask.findActivityInHistory(mStartActivity.mActivityComponent);
+                    targetTask.findActivityInHistory(mStartActivity.mActivityComponent,
+                            mStartActivity.mUserId);
             if (act != null) {
                 final Task task = act.getTask();
-                task.moveActivityToFrontLocked(act);
+                boolean actuallyMoved = task.moveActivityToFrontLocked(act);
+                if (actuallyMoved) {
+                    // Only record if the activity actually moved.
+                    mMovedToTopActivity = act;
+                }
                 act.updateOptionsLocked(mOptions);
                 deliverNewIntent(act, intentGrants);
                 act.getTaskFragment().clearLastPausedActivity();
@@ -2449,6 +2198,7 @@
 
         mInTask = null;
         mInTaskFragment = null;
+        mAddingToTaskFragment = null;
         mAddingToTask = false;
 
         mSourceRootTask = null;
@@ -2977,10 +2727,7 @@
                 newParent = candidateTf;
             }
         }
-        if (newParent.canHaveEmbeddingActivityTransition(mStartActivity)) {
-            // Make sure the embedded TaskFragment is included in the start activity transition.
-            newParent.collectEmbeddedTaskFragmentIfNeeded();
-        }
+        newParent.mTransitionController.collect(newParent);
         if (mStartActivity.getTaskFragment() == null
                 || mStartActivity.getTaskFragment() == newParent) {
             newParent.addChild(mStartActivity, POSITION_TOP);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index be155a7..8f5d8384 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -330,6 +330,7 @@
     public static final String DUMP_RECENTS_CMD = "recents";
     public static final String DUMP_RECENTS_SHORT_CMD = "r";
     public static final String DUMP_TOP_RESUMED_ACTIVITY = "top-resumed";
+    public static final String DUMP_VISIBLE_ACTIVITIES = "visible";
 
     /** This activity is not being relaunched, or being relaunched for a non-resize reason. */
     public static final int RELAUNCH_REASON_NONE = 0;
@@ -344,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;
@@ -1039,6 +1040,10 @@
         }
     }
 
+    Context getUiContext() {
+        return mUiContext;
+    }
+
     UserManagerService getUserManager() {
         if (mUserManager == null) {
             IBinder b = ServiceManager.getService(Context.USER_SERVICE);
@@ -2179,10 +2184,19 @@
         if (appThread != null) {
             callerApp = getProcessController(appThread);
         }
-        final ActivityStarter starter = getActivityStartController().obtainStarter(
-                null /* intent */, "moveTaskToFront");
-        if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid, callingPackage, -1,
-                -1, callerApp, null, false, null, null)) {
+        final BackgroundActivityStartController balController =
+                getActivityStartController().getBackgroundActivityLaunchController();
+        if (balController.shouldAbortBackgroundActivityStart(
+                callingUid,
+                callingPid,
+                callingPackage,
+                -1,
+                -1,
+                callerApp,
+                null,
+                false,
+                null,
+                null)) {
             if (!isBackgroundActivityStartsEnabled()) {
                 return;
             }
@@ -4052,6 +4066,25 @@
         }
     }
 
+    void dumpVisibleActivitiesLocked(PrintWriter pw) {
+        pw.println("ACTIVITY MANAGER VISIBLE ACTIVITIES (dumpsys activity visible)");
+        ArrayList<ActivityRecord> activities =
+                mRootWindowContainer.getDumpActivities("all", /* dumpVisibleRootTasksOnly */ true,
+                        /* dumpFocusedRootTaskOnly */ false, UserHandle.USER_ALL);
+        boolean needSeparator = false;
+        for (int i = activities.size() - 1; i >= 0; i--) {
+            ActivityRecord activity = activities.get(i);
+            if (!activity.isVisible()) {
+                continue;
+            }
+            if (needSeparator) {
+                pw.println();
+            }
+            activity.dump(pw, "", true);
+            needSeparator = true;
+        }
+    }
+
     void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
         dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage,
@@ -6284,6 +6317,8 @@
                     }
                 } else if (DUMP_TOP_RESUMED_ACTIVITY.equals(cmd)) {
                     dumpTopResumedActivityLocked(pw);
+                } else if (DUMP_VISIBLE_ACTIVITIES.equals(cmd)) {
+                    dumpVisibleActivitiesLocked(pw);
                 }
             }
         }
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/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index e80c260..fd6c974 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -119,10 +119,20 @@
                 if (appThread != null) {
                     callerApp = mService.getProcessController(appThread);
                 }
-                final ActivityStarter starter = mService.getActivityStartController().obtainStarter(
-                        null /* intent */, "moveToFront");
-                if (starter.shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                        callingPackage, -1, -1, callerApp, null, false, null, null)) {
+                final BackgroundActivityStartController balController =
+                        mService.getActivityStartController()
+                                .getBackgroundActivityLaunchController();
+                if (balController.shouldAbortBackgroundActivityStart(
+                        callingUid,
+                        callingPid,
+                        callingPackage,
+                        -1,
+                        -1,
+                        callerApp,
+                        null,
+                        false,
+                        null,
+                        null)) {
                     if (!mService.isBackgroundActivityStartsEnabled()) {
                         return;
                     }
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/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
new file mode 100644
index 0000000..d515a27
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -0,0 +1,421 @@
+/*
+ * 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;
+
+import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ACTIVITY_STARTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_ALLOW;
+import static com.android.server.wm.ActivityTaskManagerService.APP_SWITCH_FG_ONLY;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.DebugUtils;
+import android.util.Slog;
+
+import com.android.server.am.PendingIntentRecord;
+
+/**
+ * Helper class to check permissions for starting Activities.
+ *
+ * <p>This class collects all the logic to prevent malicious attempts to start activities.
+ */
+public class BackgroundActivityStartController {
+
+    private static final String TAG =
+            TAG_WITH_CLASS_NAME ? "BackgroundActivityStartController" : TAG_ATM;
+
+    private final ActivityTaskManagerService mService;
+    private final ActivityTaskSupervisor mSupervisor;
+
+    BackgroundActivityStartController(
+            final ActivityTaskManagerService service, final ActivityTaskSupervisor supervisor) {
+        mService = service;
+        mSupervisor = supervisor;
+    }
+
+    private boolean isHomeApp(int uid, @Nullable String packageName) {
+        if (mService.mHomeProcess != null) {
+            // Fast check
+            return uid == mService.mHomeProcess.mUid;
+        }
+        if (packageName == null) {
+            return false;
+        }
+        ComponentName activity =
+                mService.getPackageManagerInternalLocked()
+                        .getDefaultHomeActivity(UserHandle.getUserId(uid));
+        return activity != null && packageName.equals(activity.getPackageName());
+    }
+
+    boolean shouldAbortBackgroundActivityStart(
+            int callingUid,
+            int callingPid,
+            final String callingPackage,
+            int realCallingUid,
+            int realCallingPid,
+            WindowProcessController callerApp,
+            PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart,
+            Intent intent,
+            ActivityOptions checkedOptions) {
+        // don't abort for the most important UIDs
+        final int callingAppId = UserHandle.getAppId(callingUid);
+        final boolean useCallingUidState =
+                originatingPendingIntent == null
+                        || checkedOptions == null
+                        || !checkedOptions.getIgnorePendingIntentCreatorForegroundState();
+        if (useCallingUidState) {
+            if (callingUid == Process.ROOT_UID
+                    || callingAppId == Process.SYSTEM_UID
+                    || callingAppId == Process.NFC_UID) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed for important callingUid (" + callingUid + ")");
+                }
+                return false;
+            }
+
+            // Always allow home application to start activities.
+            if (isHomeApp(callingUid, callingPackage)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed for home app callingUid (" + callingUid + ")");
+                }
+                return false;
+            }
+
+            // IME should always be allowed to start activity, like IME settings.
+            final WindowState imeWindow =
+                    mService.mRootWindowContainer.getCurrentInputMethodWindow();
+            if (imeWindow != null && callingAppId == imeWindow.mOwnerUid) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(TAG, "Activity start allowed for active ime (" + callingUid + ")");
+                }
+                return false;
+            }
+        }
+
+        // This is used to block background activity launch even if the app is still
+        // visible to user after user clicking home button.
+        final int appSwitchState = mService.getBalAppSwitchesState();
+
+        // don't abort if the callingUid has a visible window or is a persistent system process
+        final int callingUidProcState = mService.mActiveUids.getUidState(callingUid);
+        final boolean callingUidHasAnyVisibleWindow = mService.hasActiveVisibleWindow(callingUid);
+        final boolean isCallingUidForeground =
+                callingUidHasAnyVisibleWindow
+                        || callingUidProcState == ActivityManager.PROCESS_STATE_TOP
+                        || callingUidProcState == ActivityManager.PROCESS_STATE_BOUND_TOP;
+        final boolean isCallingUidPersistentSystemProcess =
+                callingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+
+        // Normal apps with visible app window will be allowed to start activity if app switching
+        // is allowed, or apps like live wallpaper with non app visible window will be allowed.
+        final boolean appSwitchAllowedOrFg =
+                appSwitchState == APP_SWITCH_ALLOW || appSwitchState == APP_SWITCH_FG_ONLY;
+        final boolean allowCallingUidStartActivity =
+                ((appSwitchAllowedOrFg || mService.mActiveUids.hasNonAppVisibleWindow(callingUid))
+                                && callingUidHasAnyVisibleWindow)
+                        || isCallingUidPersistentSystemProcess;
+        if (useCallingUidState && allowCallingUidStartActivity) {
+            if (DEBUG_ACTIVITY_STARTS) {
+                Slog.d(
+                        TAG,
+                        "Activity start allowed: callingUidHasAnyVisibleWindow = "
+                                + callingUid
+                                + ", isCallingUidPersistentSystemProcess = "
+                                + isCallingUidPersistentSystemProcess);
+            }
+            return false;
+        }
+        // take realCallingUid into consideration
+        final int realCallingUidProcState =
+                (callingUid == realCallingUid)
+                        ? callingUidProcState
+                        : mService.mActiveUids.getUidState(realCallingUid);
+        final boolean realCallingUidHasAnyVisibleWindow =
+                (callingUid == realCallingUid)
+                        ? callingUidHasAnyVisibleWindow
+                        : mService.hasActiveVisibleWindow(realCallingUid);
+        final boolean isRealCallingUidForeground =
+                (callingUid == realCallingUid)
+                        ? isCallingUidForeground
+                        : realCallingUidHasAnyVisibleWindow
+                                || realCallingUidProcState == ActivityManager.PROCESS_STATE_TOP;
+        final int realCallingAppId = UserHandle.getAppId(realCallingUid);
+        final boolean isRealCallingUidPersistentSystemProcess =
+                (callingUid == realCallingUid)
+                        ? isCallingUidPersistentSystemProcess
+                        : (realCallingAppId == Process.SYSTEM_UID)
+                                || realCallingUidProcState
+                                        <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
+
+        // In the case of an SDK sandbox calling uid, check if the corresponding app uid has a
+        // visible window.
+        if (Process.isSdkSandboxUid(realCallingUid)) {
+            int realCallingSdkSandboxUidToAppUid =
+                    Process.getAppUidForSdkSandboxUid(UserHandle.getAppId(realCallingUid));
+
+            if (mService.hasActiveVisibleWindow(realCallingSdkSandboxUidToAppUid)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed: uid in SDK sandbox ("
+                                    + realCallingUid
+                                    + ") has visible (non-toast) window.");
+                }
+                return false;
+            }
+        }
+
+        // Legacy behavior allows to use caller foreground state to bypass BAL restriction.
+        final boolean balAllowedByPiSender =
+                PendingIntentRecord.isPendingIntentBalAllowedByCaller(checkedOptions);
+
+        if (balAllowedByPiSender && realCallingUid != callingUid) {
+            final boolean useCallerPermission =
+                    PendingIntentRecord.isPendingIntentBalAllowedByPermission(checkedOptions);
+            if (useCallerPermission
+                    && ActivityManager.checkComponentPermission(
+                                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
+                                    realCallingUid,
+                                    -1,
+                                    true)
+                            == PackageManager.PERMISSION_GRANTED) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed: realCallingUid ("
+                                    + realCallingUid
+                                    + ") has BAL permission.");
+                }
+                return false;
+            }
+
+            // don't abort if the realCallingUid has a visible window
+            // TODO(b/171459802): We should check appSwitchAllowed also
+            if (realCallingUidHasAnyVisibleWindow) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed: realCallingUid ("
+                                    + realCallingUid
+                                    + ") has visible (non-toast) window");
+                }
+                return false;
+            }
+            // if the realCallingUid is a persistent system process, abort if the IntentSender
+            // wasn't allowed to start an activity
+            if (isRealCallingUidPersistentSystemProcess && allowBackgroundActivityStart) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed: realCallingUid ("
+                                    + realCallingUid
+                                    + ") is persistent system process AND intent sender allowed "
+                                    + "(allowBackgroundActivityStart = true)");
+                }
+                return false;
+            }
+            // don't abort if the realCallingUid is an associated companion app
+            if (mService.isAssociatedCompanionApp(
+                    UserHandle.getUserId(realCallingUid), realCallingUid)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Activity start allowed: realCallingUid ("
+                                    + realCallingUid
+                                    + ") is companion app");
+                }
+                return false;
+            }
+        }
+        if (useCallingUidState) {
+            // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
+            if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
+                    == PERMISSION_GRANTED) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Background activity start allowed: START_ACTIVITIES_FROM_BACKGROUND "
+                                    + "permission granted for uid "
+                                    + callingUid);
+                }
+                return false;
+            }
+            // don't abort if the caller has the same uid as the recents component
+            if (mSupervisor.mRecentTasks.isCallerRecents(callingUid)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Background activity start allowed: callingUid ("
+                                    + callingUid
+                                    + ") is recents");
+                }
+                return false;
+            }
+            // don't abort if the callingUid is the device owner
+            if (mService.isDeviceOwner(callingUid)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Background activity start allowed: callingUid ("
+                                    + callingUid
+                                    + ") is device owner");
+                }
+                return false;
+            }
+            // don't abort if the callingUid has companion device
+            final int callingUserId = UserHandle.getUserId(callingUid);
+            if (mService.isAssociatedCompanionApp(callingUserId, callingUid)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Background activity start allowed: callingUid ("
+                                    + callingUid
+                                    + ") is companion app");
+                }
+                return false;
+            }
+            // don't abort if the callingUid has SYSTEM_ALERT_WINDOW permission
+            if (mService.hasSystemAlertWindowPermission(callingUid, callingPid, callingPackage)) {
+                Slog.w(
+                        TAG,
+                        "Background activity start for "
+                                + callingPackage
+                                + " allowed because SYSTEM_ALERT_WINDOW permission is granted.");
+                return false;
+            }
+        }
+        // If we don't have callerApp at this point, no caller was provided to startActivity().
+        // That's the case for PendingIntent-based starts, since the creator's process might not be
+        // up and alive. If that's the case, we retrieve the WindowProcessController for the send()
+        // caller if caller allows, so that we can make the decision based on its state.
+        int callerAppUid = callingUid;
+        if (callerApp == null && balAllowedByPiSender) {
+            callerApp = mService.getProcessController(realCallingPid, realCallingUid);
+            callerAppUid = realCallingUid;
+        }
+        // don't abort if the callerApp or other processes of that uid are allowed in any way
+        if (callerApp != null && useCallingUidState) {
+            // first check the original calling process
+            if (callerApp.areBackgroundActivityStartsAllowed(appSwitchState)) {
+                if (DEBUG_ACTIVITY_STARTS) {
+                    Slog.d(
+                            TAG,
+                            "Background activity start allowed: callerApp process (pid = "
+                                    + callerApp.getPid()
+                                    + ", uid = "
+                                    + callerAppUid
+                                    + ") is allowed");
+                }
+                return false;
+            }
+            // only if that one wasn't allowed, check the other ones
+            final ArraySet<WindowProcessController> uidProcesses =
+                    mService.mProcessMap.getProcesses(callerAppUid);
+            if (uidProcesses != null) {
+                for (int i = uidProcesses.size() - 1; i >= 0; i--) {
+                    final WindowProcessController proc = uidProcesses.valueAt(i);
+                    if (proc != callerApp
+                            && proc.areBackgroundActivityStartsAllowed(appSwitchState)) {
+                        if (DEBUG_ACTIVITY_STARTS) {
+                            Slog.d(
+                                    TAG,
+                                    "Background activity start allowed: process "
+                                            + proc.getPid()
+                                            + " from uid "
+                                            + callerAppUid
+                                            + " is allowed");
+                        }
+                        return false;
+                    }
+                }
+            }
+        }
+        // anything that has fallen through would currently be aborted
+        Slog.w(
+                TAG,
+                "Background activity start [callingPackage: "
+                        + callingPackage
+                        + "; callingUid: "
+                        + callingUid
+                        + "; appSwitchState: "
+                        + appSwitchState
+                        + "; isCallingUidForeground: "
+                        + isCallingUidForeground
+                        + "; callingUidHasAnyVisibleWindow: "
+                        + callingUidHasAnyVisibleWindow
+                        + "; callingUidProcState: "
+                        + DebugUtils.valueToString(
+                                ActivityManager.class, "PROCESS_STATE_", callingUidProcState)
+                        + "; isCallingUidPersistentSystemProcess: "
+                        + isCallingUidPersistentSystemProcess
+                        + "; realCallingUid: "
+                        + realCallingUid
+                        + "; isRealCallingUidForeground: "
+                        + isRealCallingUidForeground
+                        + "; realCallingUidHasAnyVisibleWindow: "
+                        + realCallingUidHasAnyVisibleWindow
+                        + "; realCallingUidProcState: "
+                        + DebugUtils.valueToString(
+                                ActivityManager.class, "PROCESS_STATE_", realCallingUidProcState)
+                        + "; isRealCallingUidPersistentSystemProcess: "
+                        + isRealCallingUidPersistentSystemProcess
+                        + "; originatingPendingIntent: "
+                        + originatingPendingIntent
+                        + "; allowBackgroundActivityStart: "
+                        + allowBackgroundActivityStart
+                        + "; intent: "
+                        + intent
+                        + "; callerApp: "
+                        + callerApp
+                        + "; inVisibleTask: "
+                        + (callerApp != null && callerApp.hasActivityInVisibleTask())
+                        + "]");
+        // log aborted activity start to TRON
+        if (mService.isActivityStartsLoggingEnabled()) {
+            mSupervisor
+                    .getActivityMetricsLogger()
+                    .logAbortedBgActivityStart(
+                            intent,
+                            callerApp,
+                            callingUid,
+                            callingPackage,
+                            callingUidProcState,
+                            callingUidHasAnyVisibleWindow,
+                            realCallingUid,
+                            realCallingUidProcState,
+                            realCallingUidHasAnyVisibleWindow,
+                            (originatingPendingIntent != null));
+        }
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index b033dca..b84b2d8 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -26,6 +26,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.util.Preconditions.checkState;
 import static com.android.server.wm.DisplayAreaProto.FEATURE_ID;
+import static com.android.server.wm.DisplayAreaProto.IS_IGNORING_ORIENTATION_REQUEST;
 import static com.android.server.wm.DisplayAreaProto.IS_ORGANIZED;
 import static com.android.server.wm.DisplayAreaProto.IS_ROOT_DISPLAY_AREA;
 import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA;
@@ -320,6 +321,7 @@
         proto.write(IS_ROOT_DISPLAY_AREA, asRootDisplayArea() != null);
         proto.write(FEATURE_ID, mFeatureId);
         proto.write(IS_ORGANIZED, isOrganized());
+        proto.write(IS_IGNORING_ORIENTATION_REQUEST, getIgnoreOrientationRequest());
         proto.end(token);
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1c90bba..7471993 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -61,6 +61,7 @@
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -94,6 +95,7 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER;
@@ -182,11 +184,13 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
@@ -336,7 +340,7 @@
     private WindowState mTmpWindow;
     private boolean mUpdateImeTarget;
     private boolean mTmpInitial;
-    private int mMaxUiWidth;
+    private int mMaxUiWidth = 0;
 
     final AppTransition mAppTransition;
     final AppTransitionController mAppTransitionController;
@@ -361,9 +365,10 @@
     // Initial display metrics.
     int mInitialDisplayWidth = 0;
     int mInitialDisplayHeight = 0;
-    int mInitialDisplayDensity = 0;
     float mInitialPhysicalXDpi = 0.0f;
     float mInitialPhysicalYDpi = 0.0f;
+    // The physical density of the display
+    int mInitialDisplayDensity = 0;
 
     private Point mPhysicalDisplaySize;
 
@@ -701,10 +706,33 @@
      */
     private boolean mInEnsureActivitiesVisible = false;
 
-    // Used to indicate that the movement of child tasks to top will not move the display to top as
-    // well and thus won't change the top resumed / focused record
+    /**
+     * Used to indicate that the movement of child tasks to top will not move the display to top as
+     * well and thus won't change the top resumed / focused record
+     */
     boolean mDontMoveToTop;
 
+    /** Used for windows that want to keep the screen awake. */
+    private PowerManager.WakeLock mHoldScreenWakeLock;
+
+    /** The current window causing mHoldScreenWakeLock to be held. */
+    private WindowState mHoldScreenWindow;
+
+    /**
+     * Used during updates to temporarily store what will become the next value for
+     * mHoldScreenWindow.
+     */
+    private WindowState mTmpHoldScreenWindow;
+
+    /** Last window that obscures all windows below. */
+    private WindowState mObscuringWindow;
+
+    /** Last window which obscured a window holding the screen locked. */
+    private WindowState mLastWakeLockObscuringWindow;
+
+    /** Last window to hold the screen locked. */
+    private WindowState mLastWakeLockHoldingWindow;
+
     /**
      * The helper of policy controller.
      *
@@ -917,7 +945,7 @@
             if (isDisplayed && w.isObscuringDisplay()) {
                 // This window completely covers everything behind it, so we want to leave all
                 // of them as undimmed (for performance reasons).
-                root.mObscuringWindow = w;
+                mObscuringWindow = w;
                 mTmpApplySurfaceChangesTransactionState.obscured = true;
             }
 
@@ -931,6 +959,15 @@
             }
 
             if (w.mHasSurface && isDisplayed) {
+                if ((w.mAttrs.flags & FLAG_KEEP_SCREEN_ON) != 0) {
+                    mTmpHoldScreenWindow = w;
+                } else if (w == mLastWakeLockHoldingWindow) {
+                    ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
+                            "handleNotObscuredLocked: %s was holding screen wakelock but no longer "
+                                    + "has FLAG_KEEP_SCREEN_ON!!! called by%s",
+                            w, Debug.getCallers(10));
+                }
+
                 final int type = w.mAttrs.type;
                 if (type == TYPE_SYSTEM_DIALOG
                         || type == TYPE_SYSTEM_ERROR
@@ -949,7 +986,9 @@
 
                 final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy()
                         .getPreferredModeId(w);
-                if (w.isFocused() && mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
+
+                if (w.getWindowingMode() != WINDOWING_MODE_PINNED
+                        && mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
                         && preferredModeId != 0) {
                     mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId;
                 }
@@ -1038,18 +1077,24 @@
         mCurrentUniqueDisplayId = display.getUniqueId();
         mOffTokenAcquirer = mRootWindowContainer.mDisplayOffTokenAcquirer;
         mWallpaperController = new WallpaperController(mWmService, this);
+        mWallpaperController.resetLargestDisplay(display);
         display.getDisplayInfo(mDisplayInfo);
         display.getMetrics(mDisplayMetrics);
         mSystemGestureExclusionLimit = mWmService.mConstants.mSystemGestureExclusionLimitDp
                 * mDisplayMetrics.densityDpi / DENSITY_DEFAULT;
         isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
         mInsetsStateController = new InsetsStateController(this);
-        mDisplayFrames = new DisplayFrames(mDisplayId, mInsetsStateController.getRawInsetsState(),
+        mDisplayFrames = new DisplayFrames(mInsetsStateController.getRawInsetsState(),
                 mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
                 calculateRoundedCornersForRotation(mDisplayInfo.rotation),
                 calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
         initializeDisplayBaseInfo();
 
+        mHoldScreenWakeLock = mWmService.mPowerManager.newWakeLock(
+                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,
+                TAG_WM + "/displayId:" + mDisplayId, mDisplayId);
+        mHoldScreenWakeLock.setReferenceCounted(false);
+
         mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
         mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
         mAppTransition.registerListenerLocked(mFixedRotationTransitionListener);
@@ -1110,6 +1155,37 @@
         mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
     }
 
+    private void beginHoldScreenUpdate() {
+        mTmpHoldScreenWindow = null;
+        mObscuringWindow = null;
+    }
+
+    private void finishHoldScreenUpdate() {
+        final boolean hold = mTmpHoldScreenWindow != null;
+        if (hold && mTmpHoldScreenWindow != mHoldScreenWindow) {
+            mHoldScreenWakeLock.setWorkSource(new WorkSource(mTmpHoldScreenWindow.mSession.mUid));
+        }
+        mHoldScreenWindow = mTmpHoldScreenWindow;
+        mTmpHoldScreenWindow = null;
+
+        final boolean state = mHoldScreenWakeLock.isHeld();
+        if (hold != state) {
+            if (hold) {
+                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to %s",
+                        mHoldScreenWindow);
+                mLastWakeLockHoldingWindow = mHoldScreenWindow;
+                mLastWakeLockObscuringWindow = null;
+                mHoldScreenWakeLock.acquire();
+            } else {
+                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by %s",
+                        mObscuringWindow);
+                mLastWakeLockHoldingWindow = null;
+                mLastWakeLockObscuringWindow = mObscuringWindow;
+                mHoldScreenWakeLock.release();
+            }
+        }
+    }
+
     @Override
     void migrateToNewSurfaceControl(Transaction t) {
         t.remove(mSurfaceControl);
@@ -1542,24 +1618,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;
@@ -1864,11 +1922,11 @@
     private void startFixedRotationTransform(WindowToken token, int rotation) {
         mTmpConfiguration.unset();
         final DisplayInfo info = computeScreenConfiguration(mTmpConfiguration, rotation);
-        final WmDisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
+        final DisplayCutout cutout = calculateDisplayCutoutForRotation(rotation);
         final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
         final PrivacyIndicatorBounds indicatorBounds =
                 calculatePrivacyIndicatorBoundsForRotation(rotation);
-        final DisplayFrames displayFrames = new DisplayFrames(mDisplayId, new InsetsState(), info,
+        final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(), info,
                 cutout, roundedCorners, indicatorBounds);
         token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
     }
@@ -2075,12 +2133,10 @@
         final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
 
         // Update application display metrics.
-        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
-        final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
+        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
         final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
 
-        final Rect appFrame = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation,
-                wmDisplayCutout);
+        final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
         mDisplayInfo.rotation = rotation;
         mDisplayInfo.logicalWidth = dw;
         mDisplayInfo.logicalHeight = dh;
@@ -2118,9 +2174,10 @@
         return mDisplayInfo;
     }
 
-    WmDisplayCutout calculateDisplayCutoutForRotation(int rotation) {
+    DisplayCutout calculateDisplayCutoutForRotation(int rotation) {
         return mDisplayCutoutCache.getOrCompute(
-                mIsSizeForced ? mBaseDisplayCutout : mInitialDisplayCutout, rotation);
+                mIsSizeForced ? mBaseDisplayCutout : mInitialDisplayCutout, rotation)
+                        .getDisplayCutout();
     }
 
     static WmDisplayCutout calculateDisplayCutoutForRotationAndDisplaySizeUncached(
@@ -2191,9 +2248,7 @@
         final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
         outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh);
         outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds());
-
-        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
-        computeScreenAppConfiguration(outConfig, dw, dh, rotation, wmDisplayCutout);
+        computeScreenAppConfiguration(outConfig, dw, dh, rotation);
 
         final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
         displayInfo.rotation = rotation;
@@ -2202,7 +2257,7 @@
         final Rect appBounds = outConfig.windowConfiguration.getAppBounds();
         displayInfo.appWidth = appBounds.width();
         displayInfo.appHeight = appBounds.height();
-        final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
+        final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
         displayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
         computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh,
                 mDisplayMetrics.density, outConfig);
@@ -2211,21 +2266,17 @@
 
     /** Compute configuration related to application without changing current display. */
     private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,
-            int rotation, WmDisplayCutout wmDisplayCutout) {
-        final DisplayFrames displayFrames =
-                mDisplayPolicy.getSimulatedDisplayFrames(rotation, dw, dh, wmDisplayCutout);
-        final Rect appFrame =
-                mDisplayPolicy.getNonDecorDisplayFrameWithSimulatedFrame(displayFrames);
+            int rotation) {
+        final DisplayPolicy.DecorInsets.Info info =
+                mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh);
         // AppBounds at the root level should mirror the app screen size.
-        outConfig.windowConfiguration.setAppBounds(appFrame);
+        outConfig.windowConfiguration.setAppBounds(info.mNonDecorFrame);
         outConfig.windowConfiguration.setRotation(rotation);
         outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
 
         final float density = mDisplayMetrics.density;
-        final Point configSize =
-                mDisplayPolicy.getConfigDisplaySizeWithSimulatedFrame(displayFrames);
-        outConfig.screenWidthDp = (int) (configSize.x / density + 0.5f);
-        outConfig.screenHeightDp = (int) (configSize.y / density + 0.5f);
+        outConfig.screenWidthDp = (int) (info.mConfigFrame.width() / density + 0.5f);
+        outConfig.screenHeightDp = (int) (info.mConfigFrame.height() / density + 0.5f);
         outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);
         outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);
 
@@ -2248,8 +2299,7 @@
         config.windowConfiguration.setWindowingMode(getWindowingMode());
         config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
 
-        computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation,
-                calculateDisplayCutoutForRotation(getRotation()));
+        computeScreenAppConfiguration(config, dw, dh, displayInfo.rotation);
 
         config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
                 | ((displayInfo.flags & Display.FLAG_ROUND) != 0
@@ -2358,9 +2408,8 @@
 
     private int reduceCompatConfigWidthSize(int curSize, int rotation,
             DisplayMetrics dm, int dw, int dh) {
-        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
-        final Rect nonDecorSize = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation,
-                wmDisplayCutout);
+        final Rect nonDecorSize =
+                mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
         dm.noncompatWidthPixels = nonDecorSize.width();
         dm.noncompatHeightPixels = nonDecorSize.height();
         float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
@@ -2409,11 +2458,8 @@
     }
 
     private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh) {
-        // Get the display cutout at this rotation.
-        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
-
         // Get the app screen size at this rotation.
-        final Rect size = mDisplayPolicy.getNonDecorDisplayFrame(dw, dh, rotation, wmDisplayCutout);
+        final Rect size = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
 
         // Compute the screen layout size class for this rotation.
         int longSize = size.width();
@@ -2429,19 +2475,21 @@
     }
 
     private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
-        final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(rotation);
-        final Point size = mDisplayPolicy.getConfigDisplaySize(dw, dh, rotation, wmDisplayCutout);
-        if (size.x < displayInfo.smallestNominalAppWidth) {
-            displayInfo.smallestNominalAppWidth = size.x;
+        final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo(
+                rotation, dw, dh);
+        final int w = info.mConfigFrame.width();
+        final int h = info.mConfigFrame.height();
+        if (w < displayInfo.smallestNominalAppWidth) {
+            displayInfo.smallestNominalAppWidth = w;
         }
-        if (size.x > displayInfo.largestNominalAppWidth) {
-            displayInfo.largestNominalAppWidth = size.x;
+        if (w > displayInfo.largestNominalAppWidth) {
+            displayInfo.largestNominalAppWidth = w;
         }
-        if (size.y < displayInfo.smallestNominalAppHeight) {
-            displayInfo.smallestNominalAppHeight = size.y;
+        if (h < displayInfo.smallestNominalAppHeight) {
+            displayInfo.smallestNominalAppHeight = h;
         }
-        if (size.y > displayInfo.largestNominalAppHeight) {
-            displayInfo.largestNominalAppHeight = size.y;
+        if (h > displayInfo.largestNominalAppHeight) {
+            displayInfo.largestNominalAppHeight = h;
         }
     }
 
@@ -2555,6 +2603,17 @@
         return mCurrentOverrideConfigurationChanges;
     }
 
+    /**
+     * @return The initial display density. This is constrained by config_maxUIWidth.
+     */
+    int getInitialDisplayDensity() {
+        int density = mInitialDisplayDensity;
+        if (mMaxUiWidth > 0 && mInitialDisplayWidth > mMaxUiWidth) {
+            density = (int) ((density * mMaxUiWidth) / (float) mInitialDisplayWidth);
+        }
+        return density;
+    }
+
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
         final int lastOrientation = getConfiguration().orientation;
@@ -2701,14 +2760,19 @@
     }
 
     private void updateDisplayFrames(boolean notifyInsetsChange) {
-        if (mDisplayFrames.update(mDisplayInfo,
-                calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
-                calculateRoundedCornersForRotation(mDisplayInfo.rotation),
-                calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation))) {
+        if (updateDisplayFrames(mDisplayFrames, mDisplayInfo.rotation,
+                mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
             mInsetsStateController.onDisplayFramesUpdated(notifyInsetsChange);
         }
     }
 
+    boolean updateDisplayFrames(DisplayFrames displayFrames, int rotation, int w, int h) {
+        return displayFrames.update(rotation, w, h,
+                calculateDisplayCutoutForRotation(rotation),
+                calculateRoundedCornersForRotation(rotation),
+                calculatePrivacyIndicatorBoundsForRotation(rotation));
+    }
+
     @Override
     void onDisplayChanged(DisplayContent dc) {
         super.onDisplayChanged(dc);
@@ -2871,6 +2935,9 @@
                         + mBaseDisplayHeight + " on display:" + getDisplayId());
             }
         }
+        if (mDisplayReady) {
+            mDisplayPolicy.mDecorInsets.invalidate();
+        }
     }
 
     /**
@@ -2883,7 +2950,7 @@
      *               so only need to configure display.
      */
     void setForcedDensity(int density, int userId) {
-        mIsDensityForced = density != mInitialDisplayDensity;
+        mIsDensityForced = density != getInitialDisplayDensity();
         final boolean updateCurrent = userId == UserHandle.USER_CURRENT;
         if (mWmService.mCurrentUserId == userId || updateCurrent) {
             mBaseDisplayDensity = density;
@@ -2894,7 +2961,7 @@
             return;
         }
 
-        if (density == mInitialDisplayDensity) {
+        if (density == getInitialDisplayDensity()) {
             density = 0;
         }
         mWmService.mDisplayWindowSettings.setForcedDensity(this, density, userId);
@@ -3188,13 +3255,18 @@
             if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
             mPointerEventDispatcher.dispose();
             setRotationAnimation(null);
+            // Unlink death from remote to clear the reference from binder -> mRemoteInsetsDeath
+            // -> this DisplayContent.
+            setRemoteInsetsController(null);
             mWmService.mAnimator.removeDisplayLocked(mDisplayId);
             mOverlayLayer.release();
+            mWindowingLayer.release();
             mInputMonitor.onDisplayRemoved();
             mWmService.mDisplayNotificationController.dispatchDisplayRemoved(this);
             mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId);
             mRootWindowContainer.mTaskSupervisor
                     .getKeyguardController().onDisplayRemoved(mDisplayId);
+            mWallpaperController.resetLargestDisplay(mDisplay);
         } finally {
             mDisplayReady = false;
         }
@@ -3452,6 +3524,16 @@
         }
 
         pw.println();
+        pw.print(prefix + "mHoldScreenWindow="); pw.print(mHoldScreenWindow);
+        pw.println();
+        pw.print(prefix + "mObscuringWindow="); pw.print(mObscuringWindow);
+        pw.println();
+        pw.print(prefix + "mLastWakeLockHoldingWindow="); pw.print(mLastWakeLockHoldingWindow);
+        pw.println();
+        pw.print(prefix + "mLastWakeLockObscuringWindow=");
+        pw.println(mLastWakeLockObscuringWindow);
+
+        pw.println();
         mWallpaperController.dump(pw, "  ");
 
         if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) {
@@ -4671,6 +4753,8 @@
     void applySurfaceChangesTransaction() {
         final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked;
 
+        beginHoldScreenUpdate();
+
         mTmpUpdateAllDrawn.clear();
 
         if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
@@ -4746,6 +4830,8 @@
             // can now be shown.
             activity.updateAllDrawn();
         }
+
+        finishHoldScreenUpdate();
     }
 
     private void getBounds(Rect out, @Rotation int rotation) {
@@ -5488,7 +5574,7 @@
             outExclusionUnrestricted.setEmpty();
         }
         final Region unhandled = Region.obtain();
-        unhandled.set(0, 0, mDisplayFrames.mDisplayWidth, mDisplayFrames.mDisplayHeight);
+        unhandled.set(0, 0, mDisplayFrames.mWidth, mDisplayFrames.mHeight);
 
         final Rect leftEdge = mInsetsStateController.getSourceProvider(ITYPE_LEFT_GESTURES)
                 .getSource().getFrame();
@@ -5765,6 +5851,8 @@
                 updateRecording();
             }
         }
+        // Notify wallpaper controller of any size changes.
+        mWallpaperController.resetLargestDisplay(mDisplay);
         // Dispatch pending Configuration to WindowContext if the associated display changes to
         // un-suspended state from suspended.
         if (isSuspendedState(lastDisplayState)
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 7ca38b8..33641f7 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -30,8 +30,6 @@
 import android.view.PrivacyIndicatorBounds;
 import android.view.RoundedCorners;
 
-import com.android.server.wm.utils.WmDisplayCutout;
-
 import java.io.PrintWriter;
 
 /**
@@ -39,8 +37,6 @@
  * @hide
  */
 public class DisplayFrames {
-    public final int mDisplayId;
-
     public final InsetsState mInsetsState;
 
     /**
@@ -54,48 +50,45 @@
      */
     public final Rect mDisplayCutoutSafe = new Rect();
 
-    public int mDisplayWidth;
-    public int mDisplayHeight;
+    public int mWidth;
+    public int mHeight;
 
     public int mRotation;
 
-    public DisplayFrames(int displayId, InsetsState insetsState, DisplayInfo info,
-            WmDisplayCutout displayCutout, RoundedCorners roundedCorners,
-            PrivacyIndicatorBounds indicatorBounds) {
-        mDisplayId = displayId;
+    public DisplayFrames(InsetsState insetsState, DisplayInfo info, DisplayCutout cutout,
+            RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds) {
         mInsetsState = insetsState;
-        update(info, displayCutout, roundedCorners, indicatorBounds);
+        update(info.rotation, info.logicalWidth, info.logicalHeight, cutout, roundedCorners,
+                indicatorBounds);
+    }
+
+    DisplayFrames() {
+        mInsetsState = new InsetsState();
     }
 
     /**
-     * This is called when {@link DisplayInfo} or {@link PrivacyIndicatorBounds} is updated.
+     * This is called if the display info may be changed, e.g. rotation, size, insets.
      *
-     * @param info the updated {@link DisplayInfo}.
-     * @param displayCutout the updated {@link DisplayCutout}.
-     * @param roundedCorners the updated {@link RoundedCorners}.
-     * @param indicatorBounds the updated {@link PrivacyIndicatorBounds}.
      * @return {@code true} if anything has been changed; {@code false} otherwise.
      */
-    public boolean update(DisplayInfo info, @NonNull WmDisplayCutout displayCutout,
+    public boolean update(int rotation, int w, int h, @NonNull DisplayCutout displayCutout,
             @NonNull RoundedCorners roundedCorners,
             @NonNull PrivacyIndicatorBounds indicatorBounds) {
         final InsetsState state = mInsetsState;
         final Rect safe = mDisplayCutoutSafe;
-        final DisplayCutout cutout = displayCutout.getDisplayCutout();
-        if (mDisplayWidth == info.logicalWidth && mDisplayHeight == info.logicalHeight
-                && mRotation == info.rotation
-                && state.getDisplayCutout().equals(cutout)
+        if (mRotation == rotation && mWidth == w && mHeight == h
+                && mInsetsState.getDisplayCutout().equals(displayCutout)
                 && state.getRoundedCorners().equals(roundedCorners)
                 && state.getPrivacyIndicatorBounds().equals(indicatorBounds)) {
             return false;
         }
-        mDisplayWidth = info.logicalWidth;
-        mDisplayHeight = info.logicalHeight;
-        mRotation = info.rotation;
+        mRotation = rotation;
+        mWidth = w;
+        mHeight = h;
         final Rect unrestricted = mUnrestricted;
-        unrestricted.set(0, 0, mDisplayWidth, mDisplayHeight);
+        unrestricted.set(0, 0, w, h);
         state.setDisplayFrame(unrestricted);
-        state.setDisplayCutout(cutout);
+        state.setDisplayCutout(displayCutout);
         state.setRoundedCorners(roundedCorners);
         state.setPrivacyIndicatorBounds(indicatorBounds);
         state.getDisplayCutoutSafe(safe);
@@ -132,7 +125,6 @@
     }
 
     public void dump(String prefix, PrintWriter pw) {
-        pw.println(prefix + "DisplayFrames w=" + mDisplayWidth + " h=" + mDisplayHeight
-                + " r=" + mRotation);
+        pw.println(prefix + "DisplayFrames w=" + mWidth + " h=" + mHeight + " r=" + mRotation);
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 508e6dc..e780606 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -19,19 +19,15 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.view.Display.TYPE_INTERNAL;
-import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
 import static android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES;
 import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
 import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
 import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
 import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
 import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
@@ -107,7 +103,6 @@
 import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.gui.DropInputMode;
@@ -132,8 +127,6 @@
 import android.view.InsetsState;
 import android.view.InsetsState.InternalInsetsType;
 import android.view.InsetsVisibilities;
-import android.view.PrivacyIndicatorBounds;
-import android.view.RoundedCorners;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewDebug;
@@ -151,7 +144,6 @@
 import com.android.internal.policy.ForceShowNavBarSettingsObserver;
 import com.android.internal.policy.GestureNavigationSettingsObserver;
 import com.android.internal.policy.ScreenDecorationsUtils;
-import com.android.internal.policy.SystemBarUtils;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.statusbar.LetterboxDetails;
 import com.android.internal.util.ScreenshotHelper;
@@ -166,7 +158,6 @@
 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wallpaper.WallpaperManagerInternal;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -242,6 +233,8 @@
 
     private final SystemGesturesPointerEventListener mSystemGestures;
 
+    final DecorInsets mDecorInsets;
+
     private volatile int mLidState = LID_ABSENT;
     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
     private volatile boolean mHdmiPlugged;
@@ -266,7 +259,6 @@
 
     private WindowState mStatusBar = null;
     private volatile WindowState mNotificationShade;
-    private final int[] mStatusBarHeightForRotation = new int[4];
     private WindowState mNavigationBar = null;
     @NavigationBarPosition
     private int mNavigationBarPosition = NAV_BAR_BOTTOM;
@@ -353,7 +345,6 @@
 
     private static final Rect sTmpRect = new Rect();
     private static final Rect sTmpRect2 = new Rect();
-    private static final Rect sTmpLastParentFrame = new Rect();
     private static final Rect sTmpDisplayCutoutSafe = new Rect();
     private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames();
 
@@ -362,6 +353,7 @@
     private WindowState mTopFullscreenOpaqueWindowState;
     private boolean mTopIsFullscreen;
     private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
+    private boolean mForceConsumeSystemBars;
     private boolean mForceShowSystemBars;
 
     private boolean mShowingDream;
@@ -390,16 +382,6 @@
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
 
-    // TODO (b/235842600): Use public type once we can treat task bar as navigation bar.
-    private static final int[] STABLE_TYPES = new int[]{
-            ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT, ITYPE_BOTTOM_DISPLAY_CUTOUT,
-            ITYPE_LEFT_DISPLAY_CUTOUT, ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR, ITYPE_CLIMATE_BAR
-    };
-    private static final int[] NON_DECOR_TYPES = new int[]{
-            ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT, ITYPE_BOTTOM_DISPLAY_CUTOUT,
-            ITYPE_LEFT_DISPLAY_CUTOUT, ITYPE_NAVIGATION_BAR
-    };
-
     private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
 
     private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
@@ -439,10 +421,11 @@
         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;
+        mDecorInsets = new DecorInsets(displayContent);
         mLock = service.getWindowManagerLock();
 
         final int displayId = displayContent.getDisplayId();
@@ -1225,7 +1208,7 @@
                                     Math.max(displayFrames.mDisplayCutoutSafe.left, 0);
                             inOutFrame.left = 0;
                             inOutFrame.top = 0;
-                            inOutFrame.bottom = displayFrames.mDisplayHeight;
+                            inOutFrame.bottom = displayFrames.mHeight;
                             inOutFrame.right = leftSafeInset + mLeftGestureInset;
                         });
                 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
@@ -1235,8 +1218,8 @@
                                             displayFrames.mUnrestricted.right);
                             inOutFrame.left = rightSafeInset - mRightGestureInset;
                             inOutFrame.top = 0;
-                            inOutFrame.bottom = displayFrames.mDisplayHeight;
-                            inOutFrame.right = displayFrames.mDisplayWidth;
+                            inOutFrame.bottom = displayFrames.mHeight;
+                            inOutFrame.right = displayFrames.mWidth;
                         });
                 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win,
                         (displayFrames, windowContainer, inOutFrame) -> {
@@ -1427,11 +1410,6 @@
         return Math.max(statusBarHeight, displayFrames.mDisplayCutoutSafe.top);
     }
 
-    @VisibleForTesting
-    int getStatusBarHeightForRotation(@Surface.Rotation int rotation) {
-        return SystemBarUtils.getStatusBarHeightForRotation(mUiContext, rotation);
-    }
-
     WindowState getStatusBar() {
         return mStatusBar != null ? mStatusBar : mStatusBarAlt;
     }
@@ -1561,6 +1539,13 @@
     }
 
     /**
+     * @return true if the system bars are forced to be consumed
+     */
+    public boolean areSystemBarsForcedConsumedLw() {
+        return mForceConsumeSystemBars;
+    }
+
+    /**
      * @return true if the system bars are forced to stay visible
      */
     public boolean areSystemBarsForcedShownLw() {
@@ -1920,25 +1905,11 @@
 
         final Resources res = getCurrentUserResources();
         final int portraitRotation = displayRotation.getPortraitRotation();
-        final int upsideDownRotation = displayRotation.getUpsideDownRotation();
-        final int landscapeRotation = displayRotation.getLandscapeRotation();
-        final int seascapeRotation = displayRotation.getSeascapeRotation();
 
         if (hasStatusBar()) {
-            mStatusBarHeightForRotation[portraitRotation] =
-                    mStatusBarHeightForRotation[upsideDownRotation] =
-                            getStatusBarHeightForRotation(portraitRotation);
-            mStatusBarHeightForRotation[landscapeRotation] =
-                    getStatusBarHeightForRotation(landscapeRotation);
-            mStatusBarHeightForRotation[seascapeRotation] =
-                    getStatusBarHeightForRotation(seascapeRotation);
             mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize(
                     R.dimen.display_cutout_touchable_region_size);
         } else {
-            mStatusBarHeightForRotation[portraitRotation] =
-                    mStatusBarHeightForRotation[upsideDownRotation] =
-                            mStatusBarHeightForRotation[landscapeRotation] =
-                                    mStatusBarHeightForRotation[seascapeRotation] = 0;
             mDisplayCutoutTouchableRegionSize = 0;
         }
 
@@ -2044,33 +2015,9 @@
     }
 
     /**
-     * Return the display frame available after excluding any screen decorations that could never be
-     * removed in Honeycomb. That is, system bar or button bar.
-     *
-     * @return display frame excluding all non-decor insets.
-     */
-    Rect getNonDecorDisplayFrame(int fullWidth, int fullHeight, int rotation,
-            WmDisplayCutout cutout) {
-        final DisplayFrames displayFrames =
-                getSimulatedDisplayFrames(rotation, fullWidth, fullHeight, cutout);
-        return getNonDecorDisplayFrameWithSimulatedFrame(displayFrames);
-    }
-
-    Rect getNonDecorDisplayFrameWithSimulatedFrame(DisplayFrames displayFrames) {
-        final Rect nonDecorInsets =
-                getInsetsWithInternalTypes(displayFrames, NON_DECOR_TYPES).toRect();
-        final Rect displayFrame = new Rect(displayFrames.mInsetsState.getDisplayFrame());
-        displayFrame.inset(nonDecorInsets);
-        return displayFrame;
-    }
-
-    /**
      * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
      * is used for spacing to show additional buttons on the navigation bar (such as the ime
-     * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
-     * height that we send to the app as content insets that can be smaller.
-     * <p>
-     * In car mode it will return the same height as {@link #getNavigationBarHeight}
+     * switcher when ime is visible).
      *
      * @param rotation specifies rotation to return dimension from
      * @return navigation bar frame height
@@ -2083,26 +2030,6 @@
     }
 
     /**
-     * Return the available screen size that we should report for the
-     * configuration.  This must be no larger than
-     * {@link #getNonDecorDisplayFrame(int, int, int, DisplayCutout)}; it may be smaller
-     * than that to account for more transient decoration like a status bar.
-     */
-    public Point getConfigDisplaySize(int fullWidth, int fullHeight, int rotation,
-            WmDisplayCutout wmDisplayCutout) {
-        final DisplayFrames displayFrames = getSimulatedDisplayFrames(rotation, fullWidth,
-                fullHeight, wmDisplayCutout);
-        return getConfigDisplaySizeWithSimulatedFrame(displayFrames);
-    }
-
-    Point getConfigDisplaySizeWithSimulatedFrame(DisplayFrames displayFrames) {
-        final Insets insets = getInsetsWithInternalTypes(displayFrames, STABLE_TYPES);
-        Rect configFrame = new Rect(displayFrames.mInsetsState.getDisplayFrame());
-        configFrame.inset(insets);
-        return new Point(configFrame.width(), configFrame.height());
-    }
-
-    /**
      * Return corner radius in pixels that should be used on windows in order to cover the display.
      *
      * The radius is only valid for internal displays, since the corner radius of external displays
@@ -2117,89 +2044,150 @@
         return mShowingDream;
     }
 
-    /**
-     * Calculates the stable insets if we already have the non-decor insets.
-     *
-     * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
-     * @param rotation The current display rotation.
-     */
-    void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
-        inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
+    /** The latest insets and frames for screen configuration calculation. */
+    static class DecorInsets {
+        static class Info {
+            /**
+             * The insets for the areas that could never be removed, i.e. display cutout and
+             * navigation bar. Note that its meaning is actually "decor insets". The "non" is just
+             * because it is used to calculate {@link #mNonDecorFrame}.
+             */
+            final Rect mNonDecorInsets = new Rect();
+
+            /**
+             * The stable insets that can affect configuration. The sources are usually from
+             * display cutout, navigation bar, and status bar.
+             */
+            final Rect mConfigInsets = new Rect();
+
+            /** The display frame available after excluding {@link #mNonDecorInsets}. */
+            final Rect mNonDecorFrame = new Rect();
+
+            /**
+             * The available (stable) screen size that we should report for the configuration.
+             * This must be no larger than {@link #mNonDecorFrame}; it may be smaller than that
+             * to account for more transient decoration like a status bar.
+             */
+            final Rect mConfigFrame = new Rect();
+
+            private boolean mNeedUpdate = true;
+
+            void update(DisplayContent dc, int rotation, int w, int h) {
+                final DisplayFrames df = new DisplayFrames();
+                dc.updateDisplayFrames(df, rotation, w, h);
+                dc.getDisplayPolicy().simulateLayoutDisplay(df);
+                final InsetsState insetsState = df.mInsetsState;
+                final Rect displayFrame = insetsState.getDisplayFrame();
+                final Insets decor = calculateDecorInsetsWithInternalTypes(insetsState);
+                final Insets statusBar = insetsState.calculateInsets(displayFrame,
+                        Type.statusBars(), true /* ignoreVisibility */);
+                mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom);
+                mConfigInsets.set(Math.max(statusBar.left, decor.left),
+                        Math.max(statusBar.top, decor.top),
+                        Math.max(statusBar.right, decor.right),
+                        Math.max(statusBar.bottom, decor.bottom));
+                mNonDecorFrame.set(displayFrame);
+                mNonDecorFrame.inset(mNonDecorInsets);
+                mConfigFrame.set(displayFrame);
+                mConfigFrame.inset(mConfigInsets);
+                mNeedUpdate = false;
+            }
+
+            void set(Info other) {
+                mNonDecorInsets.set(other.mNonDecorInsets);
+                mConfigInsets.set(other.mConfigInsets);
+                mNonDecorFrame.set(other.mNonDecorFrame);
+                mConfigFrame.set(other.mConfigFrame);
+                mNeedUpdate = false;
+            }
+
+            @Override
+            public String toString() {
+                return "{nonDecorInsets=" + mNonDecorInsets
+                        + ", configInsets=" + mConfigInsets
+                        + ", nonDecorFrame=" + mNonDecorFrame
+                        + ", configFrame=" + mConfigFrame + '}';
+            }
+        }
+
+        // TODO (b/235842600): Use public type once we can treat task bar as navigation bar.
+        static final int[] INTERNAL_DECOR_TYPES;
+        static {
+            final ArraySet<Integer> decorTypes = InsetsState.toInternalType(
+                    Type.displayCutout() | Type.navigationBars());
+            decorTypes.remove(ITYPE_EXTRA_NAVIGATION_BAR);
+            INTERNAL_DECOR_TYPES = new int[decorTypes.size()];
+            for (int i = 0; i < INTERNAL_DECOR_TYPES.length; i++) {
+                INTERNAL_DECOR_TYPES[i] = decorTypes.valueAt(i);
+            }
+        }
+
+        private final DisplayContent mDisplayContent;
+        private final Info[] mInfoForRotation = new Info[4];
+        final Info mTmpInfo = new Info();
+
+        DecorInsets(DisplayContent dc) {
+            mDisplayContent = dc;
+            for (int i = mInfoForRotation.length - 1; i >= 0; i--) {
+                mInfoForRotation[i] = new Info();
+            }
+        }
+
+        Info get(int rotation, int w, int h) {
+            final Info info = mInfoForRotation[rotation];
+            if (info.mNeedUpdate) {
+                info.update(mDisplayContent, rotation, w, h);
+            }
+            return info;
+        }
+
+        /** Called when the screen decor insets providers have changed. */
+        void invalidate() {
+            for (Info info : mInfoForRotation) {
+                info.mNeedUpdate = true;
+            }
+        }
+
+        // TODO (b/235842600): Remove this method once we can treat task bar as navigation bar.
+        private static Insets calculateDecorInsetsWithInternalTypes(InsetsState state) {
+            final Rect frame = state.getDisplayFrame();
+            Insets insets = Insets.NONE;
+            for (int i = INTERNAL_DECOR_TYPES.length - 1; i >= 0; i--) {
+                final InsetsSource source = state.peekSource(INTERNAL_DECOR_TYPES[i]);
+                if (source != null) {
+                    insets = Insets.max(source.calculateInsets(frame, true /* ignoreVisibility */),
+                            insets);
+                }
+            }
+            return insets;
+        }
     }
 
     /**
-     * Calculates the stable insets without running a layout.
-     *
-     * @param displayRotation the current display rotation
-     * @param displayWidth full display width
-     * @param displayHeight full display height
-     * @param displayCutout the current display cutout
-     * @param outInsets the insets to return
+     * If the decor insets changes, the display configuration may be affected. The caller should
+     * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}.
      */
-    public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
-            WmDisplayCutout displayCutout, Rect outInsets) {
-        final DisplayFrames displayFrames = getSimulatedDisplayFrames(displayRotation,
-                displayWidth, displayHeight, displayCutout);
-        getStableInsetsWithSimulatedFrame(displayFrames, outInsets);
+    boolean updateDecorInsetsInfoIfNeeded(WindowState win) {
+        if (!win.providesNonDecorInsets()) {
+            return false;
+        }
+        final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames;
+        final int rotation = displayFrames.mRotation;
+        final int dw = displayFrames.mWidth;
+        final int dh = displayFrames.mHeight;
+        final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo;
+        newInfo.update(mDisplayContent, rotation, dw, dh);
+        final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh);
+        if (newInfo.mNonDecorFrame.equals(currentInfo.mNonDecorFrame)) {
+            return false;
+        }
+        mDecorInsets.invalidate();
+        mDecorInsets.mInfoForRotation[rotation].set(newInfo);
+        return true;
     }
 
-    void getStableInsetsWithSimulatedFrame(DisplayFrames displayFrames, Rect outInsets) {
-        // Navigation bar, status bar, and cutout.
-        outInsets.set(getInsetsWithInternalTypes(displayFrames, STABLE_TYPES).toRect());
-    }
-
-    /**
-     * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
-     * bar or button bar. See {@link #getNonDecorDisplayFrame}.
-     *
-     * @param displayRotation the current display rotation
-     * @param fullWidth the width of the display, including all insets
-     * @param fullHeight the height of the display, including all insets
-     * @param cutout the current display cutout
-     * @param outInsets the insets to return
-     */
-    public void getNonDecorInsetsLw(int displayRotation, int fullWidth, int fullHeight,
-            WmDisplayCutout cutout, Rect outInsets) {
-        final DisplayFrames displayFrames =
-                getSimulatedDisplayFrames(displayRotation, fullWidth, fullHeight, cutout);
-        getNonDecorInsetsWithSimulatedFrame(displayFrames, outInsets);
-    }
-
-    void getNonDecorInsetsWithSimulatedFrame(DisplayFrames displayFrames, Rect outInsets) {
-        outInsets.set(getInsetsWithInternalTypes(displayFrames, NON_DECOR_TYPES).toRect());
-    }
-
-    DisplayFrames getSimulatedDisplayFrames(int displayRotation, int fullWidth,
-            int fullHeight, WmDisplayCutout cutout) {
-        final DisplayInfo info = new DisplayInfo(mDisplayContent.getDisplayInfo());
-        info.rotation = displayRotation;
-        info.logicalWidth = fullWidth;
-        info.logicalHeight = fullHeight;
-        info.displayCutout = cutout.getDisplayCutout();
-        final RoundedCorners roundedCorners =
-                mDisplayContent.calculateRoundedCornersForRotation(displayRotation);
-        final PrivacyIndicatorBounds indicatorBounds =
-                mDisplayContent.calculatePrivacyIndicatorBoundsForRotation(displayRotation);
-        final DisplayFrames displayFrames = new DisplayFrames(getDisplayId(), new InsetsState(),
-                info, cutout, roundedCorners, indicatorBounds);
-        simulateLayoutDisplay(displayFrames);
-        return displayFrames;
-    }
-
-    @VisibleForTesting
-    Insets getInsets(DisplayFrames displayFrames, @InsetsType int type) {
-        final InsetsState state = displayFrames.mInsetsState;
-        final Insets insets = state.calculateInsets(state.getDisplayFrame(), type,
-                true /* ignoreVisibility */);
-        return insets;
-    }
-
-    Insets getInsetsWithInternalTypes(DisplayFrames displayFrames,
-            @InternalInsetsType int[] types) {
-        final InsetsState state = displayFrames.mInsetsState;
-        final Insets insets = state.calculateInsetsWithInternalTypes(state.getDisplayFrame(), types,
-                true /* ignoreVisibility */);
-        return insets;
+    DecorInsets.Info getDecorInsetsInfo(int rotation, int w, int h) {
+        return mDecorInsets.get(rotation, w, h);
     }
 
     @NavigationBarPosition
@@ -2462,6 +2450,10 @@
         // We need to force showing system bars when the multi-window or freeform root task is
         // visible.
         mForceShowSystemBars = multiWindowTaskVisible || freeformRootTaskVisible;
+        // We need to force the consumption of the system bars if they are force shown or if they
+        // are controlled by a remote insets controller.
+        mForceConsumeSystemBars = mForceShowSystemBars
+                || mDisplayContent.getInsetsPolicy().remoteInsetsControllerControlsSystemBars(win);
         mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
 
         final boolean topAppHidesStatusBar = topAppHidesStatusBar();
@@ -2838,6 +2830,11 @@
         pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
         pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars=");
         pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
+        pw.print(prefix); pw.println("mDecorInsetsInfo:");
+        for (int rotation = 0; rotation < mDecorInsets.mInfoForRotation.length; rotation++) {
+            final DecorInsets.Info info = mDecorInsets.mInfoForRotation[rotation];
+            pw.println(prefixInner + Surface.rotationToString(rotation) + "=" + info);
+        }
         mSystemGestures.dump(pw, prefix);
 
         pw.print(prefix); pw.println("Looper state:");
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index 11bcd8c..9462d4f7 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -276,7 +276,7 @@
         final int width = hasSizeOverride ? settings.mForcedWidth : dc.mInitialDisplayWidth;
         final int height = hasSizeOverride ? settings.mForcedHeight : dc.mInitialDisplayHeight;
         final int density = hasDensityOverride ? settings.mForcedDensity
-                : dc.mInitialDisplayDensity;
+                : dc.getInitialDisplayDensity();
         dc.updateBaseDisplayMetrics(width, height, density, dc.mBaseDisplayPhysicalXDpi,
                 dc.mBaseDisplayPhysicalYDpi);
 
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/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index ed771c2..ac1fbc3 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -34,6 +34,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.SparseArray;
+import android.view.InsetsSource;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.InsetsState.InternalInsetsType;
@@ -44,6 +45,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 /**
  * Manages global window inset state in the system represented by {@link InsetsState}.
@@ -86,8 +88,17 @@
         }
     };
 
+    private final Function<Integer, WindowContainerInsetsSourceProvider> mSourceProviderFunc;
+
     InsetsStateController(DisplayContent displayContent) {
         mDisplayContent = displayContent;
+        mSourceProviderFunc = type -> {
+            final InsetsSource source = mState.getSource(type);
+            if (type == ITYPE_IME) {
+                return new ImeInsetsSourceProvider(source, this, mDisplayContent);
+            }
+            return new WindowContainerInsetsSourceProvider(source, this, mDisplayContent);
+        };
     }
 
     InsetsState getRawInsetsState() {
@@ -115,15 +126,7 @@
      * @return The provider of a specific type.
      */
     WindowContainerInsetsSourceProvider getSourceProvider(@InternalInsetsType int type) {
-        if (type == ITYPE_IME) {
-            return mProviders.computeIfAbsent(type,
-                    key -> new ImeInsetsSourceProvider(
-                            mState.getSource(key), this, mDisplayContent));
-        } else {
-            return mProviders.computeIfAbsent(type,
-                    key -> new WindowContainerInsetsSourceProvider(mState.getSource(key), this,
-                            mDisplayContent));
-        }
+        return mProviders.computeIfAbsent(type, mSourceProviderFunc);
     }
 
     ImeInsetsSourceProvider getImeSourceProvider() {
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 6602d29..4f506a5 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -14,3 +14,6 @@
 [email protected]
 [email protected]
 [email protected]
+
+per-file BackgroundActivityStartController.java = set noparent
+per-file BackgroundActivityStartController.java = [email protected], [email protected], [email protected], [email protected], [email protected]
diff --git a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
index 3f6fb622..e3a2065 100644
--- a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
+++ b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
@@ -22,6 +22,8 @@
 import android.util.SparseArray;
 import android.view.DisplayInfo;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -52,19 +54,21 @@
 
 
     /**
-     * Returns, for the given displayId, a set of display infos. Set contains each supported device
-     * state.
+     * Returns, for the given displayId, a list of unique display infos. List contains each
+     * supported device state.
+     * <p>List contents are guaranteed to be unique, but returned as a list rather than a set to
+     * minimize copies needed to make an iteraable data structure.
      */
-    public Set<DisplayInfo> getPossibleDisplayInfos(int displayId) {
+    public List<DisplayInfo> getPossibleDisplayInfos(int displayId) {
         // Update display infos before returning, since any cached values would have been removed
         // in response to any display event. This model avoids re-computing the cache for every
         // display change event (which occurs extremely frequently in the normal usage of the
         // device).
         updatePossibleDisplayInfos(displayId);
         if (!mDisplayInfos.contains(displayId)) {
-            return new ArraySet<>();
+            return new ArrayList<>();
         }
-        return Set.copyOf(mDisplayInfos.get(displayId));
+        return List.copyOf(mDisplayInfos.get(displayId));
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 077f8b5..b3f3548 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -28,7 +28,6 @@
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
@@ -176,15 +175,9 @@
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
 
     private Object mLastWindowFreezeSource = null;
-    private Session mHoldScreen = null;
     private float mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
     private long mUserActivityTimeout = -1;
     private boolean mUpdateRotation = false;
-    // Following variables are for debugging screen wakelock only.
-    // Last window that requires screen wakelock
-    WindowState mHoldScreenWindow = null;
-    // Last window that obscures all windows below
-    WindowState mObscuringWindow = null;
     // Only set while traversing the default display based on its content.
     // Affects the behavior of mirroring on secondary displays.
     private boolean mObscureApplicationContentOnSecondaryDisplays = false;
@@ -801,7 +794,6 @@
                     UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
         }
 
-        mHoldScreen = null;
         mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         mUserActivityTimeout = -1;
         mObscureApplicationContentOnSecondaryDisplays = false;
@@ -914,7 +906,6 @@
             }
         }
 
-        mWmService.setHoldScreenLocked(mHoldScreen);
         if (!mWmService.mDisplayFrozen) {
             final float brightnessOverride = mScreenBrightnessOverride < PowerManager.BRIGHTNESS_MIN
                     || mScreenBrightnessOverride > PowerManager.BRIGHTNESS_MAX
@@ -994,9 +985,6 @@
     }
 
     private void applySurfaceChangesTransaction() {
-        mHoldScreenWindow = null;
-        mObscuringWindow = null;
-
         // TODO(multi-display): Support these features on secondary screens.
         final DisplayContent defaultDc = mDefaultDisplay;
         final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
@@ -1071,15 +1059,6 @@
             }
         }
         if (w.mHasSurface && canBeSeen) {
-            if ((attrFlags & FLAG_KEEP_SCREEN_ON) != 0) {
-                mHoldScreen = w.mSession;
-                mHoldScreenWindow = w;
-            } else if (w == mWmService.mLastWakeLockHoldingWindow) {
-                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON,
-                        "handleNotObscuredLocked: %s was holding screen wakelock but no longer "
-                                + "has FLAG_KEEP_SCREEN_ON!!! called by%s",
-                        w, Debug.getCallers(10));
-            }
             if (!syswin && w.mAttrs.screenBrightness >= 0
                     && Float.isNaN(mScreenBrightnessOverride)) {
                 mScreenBrightnessOverride = w.mAttrs.screenBrightness;
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/Task.java b/services/core/java/com/android/server/wm/Task.java
index e38f5fe..728102e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -60,10 +60,7 @@
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
 import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
@@ -1405,13 +1402,15 @@
 
     /**
      * Reorder the history task so that the passed activity is brought to the front.
+     * @return whether it was actually moved (vs already being top).
      */
-    final void moveActivityToFrontLocked(ActivityRecord newTop) {
+    final boolean moveActivityToFrontLocked(ActivityRecord newTop) {
         ProtoLog.i(WM_DEBUG_ADD_REMOVE, "Removing and adding activity %s to root task at top "
                 + "callers=%s", newTop, Debug.getCallers(4));
-
+        int origDist = getDistanceFromTop(newTop);
         positionChildAtTop(newTop);
         updateEffectiveIntent();
+        return getDistanceFromTop(newTop) != origDist;
     }
 
     @Override
@@ -1436,6 +1435,13 @@
         final TaskFragment childTaskFrag = child.asTaskFragment();
         if (childTaskFrag != null && childTaskFrag.asTask() == null) {
             childTaskFrag.setMinDimensions(mMinWidth, mMinHeight);
+
+            // The starting window should keep covering its task when a pure TaskFragment is added
+            // because its bounds may not fill the task.
+            final ActivityRecord top = getTopMostActivity();
+            if (top != null) {
+                top.associateStartingWindowWithTaskIfNeeded();
+            }
         }
     }
 
@@ -1603,14 +1609,14 @@
         }
     }
 
-    ActivityRecord performClearTop(ActivityRecord newR, int launchFlags) {
+    ActivityRecord performClearTop(ActivityRecord newR, int launchFlags, int[] finishCount) {
         // The task should be preserved for putting new activity in case the last activity is
         // finished if it is normal launch mode and not single top ("clear-task-top").
         mReuseTask = true;
         mTaskSupervisor.beginDeferResume();
         final ActivityRecord result;
         try {
-            result = clearTopActivities(newR, launchFlags);
+            result = clearTopActivities(newR, launchFlags, finishCount);
         } finally {
             mTaskSupervisor.endDeferResume();
             mReuseTask = false;
@@ -1626,14 +1632,19 @@
      * activities on top of it and return the instance.
      *
      * @param newR Description of the new activity being started.
+     * @param finishCount 1-element array that will be populated with the number of activities
+     *                    that have been finished.
      * @return Returns the existing activity in the task that performs the clear-top operation,
      * or {@code null} if none was found.
      */
-    private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags) {
-        final ActivityRecord r = findActivityInHistory(newR.mActivityComponent);
+    private ActivityRecord clearTopActivities(ActivityRecord newR, int launchFlags,
+            int[] finishCount) {
+        final ActivityRecord r = findActivityInHistory(newR.mActivityComponent, newR.mUserId);
         if (r == null) return null;
 
-        final PooledPredicate f = PooledLambda.obtainPredicate(Task::finishActivityAbove,
+        final PooledPredicate f = PooledLambda.obtainPredicate(
+                (ActivityRecord ar, ActivityRecord boundaryActivity) ->
+                        finishActivityAbove(ar, boundaryActivity, finishCount),
                 PooledLambda.__(ActivityRecord.class), r);
         forAllActivities(f);
         f.recycle();
@@ -1651,7 +1662,8 @@
         return r;
     }
 
-    private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity) {
+    private static boolean finishActivityAbove(ActivityRecord r, ActivityRecord boundaryActivity,
+            @NonNull int[] finishCount) {
         // Stop operation once we reach the boundary activity.
         if (r == boundaryActivity) return true;
 
@@ -1662,6 +1674,7 @@
                 // TODO: Why is this updating the boundary activity vs. the current activity???
                 boundaryActivity.updateOptionsLocked(opts);
             }
+            finishCount[0] += 1;
             r.finishIfPossible("clear-task-stack", false /* oomAdj */);
         }
 
@@ -1746,17 +1759,18 @@
      * Find the activity in the history task within the given task.  Returns
      * the index within the history at which it's found, or < 0 if not found.
      */
-    ActivityRecord findActivityInHistory(ComponentName component) {
+    ActivityRecord findActivityInHistory(ComponentName component, int userId) {
         final PooledPredicate p = PooledLambda.obtainPredicate(Task::matchesActivityInHistory,
-                PooledLambda.__(ActivityRecord.class), component);
+                PooledLambda.__(ActivityRecord.class), component, userId);
         final ActivityRecord r = getActivity(p);
         p.recycle();
         return r;
     }
 
     private static boolean matchesActivityInHistory(
-            ActivityRecord r, ComponentName activityComponent) {
-        return !r.finishing && r.mActivityComponent.equals(activityComponent);
+            ActivityRecord r, ComponentName activityComponent, int userId) {
+        return !r.finishing && r.mActivityComponent.equals(activityComponent)
+                && r.mUserId == userId;
     }
 
     /** Updates the last task description values. */
@@ -4445,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) {
@@ -4966,23 +4988,17 @@
                 dc.prepareAppTransition(TRANSIT_NONE);
                 mTaskSupervisor.mNoAnimActivities.add(r);
             } else {
-                int transit = TRANSIT_OLD_ACTIVITY_OPEN;
-                if (newTask) {
-                    if (r.mLaunchTaskBehind) {
-                        transit = TRANSIT_OLD_TASK_OPEN_BEHIND;
-                    } else {
-                        // If a new task is being launched, then mark the existing top activity as
-                        // supporting picture-in-picture while pausing only if the starting activity
-                        // would not be considered an overlay on top of the current activity
-                        // (eg. not fullscreen, or the assistant)
-                        enableEnterPipOnTaskSwitch(pipCandidate,
-                                null /* toFrontTask */, r, options);
-                        transit = TRANSIT_OLD_TASK_OPEN;
-                    }
-                }
                 dc.prepareAppTransition(TRANSIT_OPEN);
                 mTaskSupervisor.mNoAnimActivities.remove(r);
             }
+            if (newTask && !r.mLaunchTaskBehind) {
+                // If a new task is being launched, then mark the existing top activity as
+                // supporting picture-in-picture while pausing only if the starting activity
+                // would not be considered an overlay on top of the current activity
+                // (eg. not fullscreen, or the assistant)
+                enableEnterPipOnTaskSwitch(pipCandidate,
+                        null /* toFrontTask */, r, options);
+            }
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 8872b35..f784f71 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -97,8 +97,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.wm.utils.WmDisplayCutout;
+import com.android.server.pm.pkg.AndroidPackage;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -298,10 +297,11 @@
 
     final Point mLastSurfaceSize = new Point();
 
-    private final Rect mTmpInsets = new Rect();
     private final Rect mTmpBounds = new Rect();
     private final Rect mTmpFullBounds = new Rect();
+    /** For calculating screenWidthDp and screenWidthDp, i.e. the area without the system bars. */
     private final Rect mTmpStableBounds = new Rect();
+    /** For calculating app bounds, i.e. the area without the nav bar and display cutout. */
     private final Rect mTmpNonDecorBounds = new Rect();
 
     //TODO(b/207481538) Remove once the infrastructure to support per-activity screenshot is
@@ -2202,21 +2202,16 @@
             DisplayInfo displayInfo) {
         outNonDecorBounds.set(bounds);
         outStableBounds.set(bounds);
-        final Task rootTask = getRootTaskFragment().asTask();
-        if (rootTask == null || rootTask.mDisplayContent == null) {
+        if (mDisplayContent == null) {
             return;
         }
         mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
 
-        final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
-        final WmDisplayCutout cutout =
-                rootTask.mDisplayContent.calculateDisplayCutoutForRotation(displayInfo.rotation);
-        final DisplayFrames displayFrames = policy.getSimulatedDisplayFrames(displayInfo.rotation,
-                displayInfo.logicalWidth, displayInfo.logicalHeight, cutout);
-        policy.getNonDecorInsetsWithSimulatedFrame(displayFrames, mTmpInsets);
-        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
-        policy.getStableInsetsWithSimulatedFrame(displayFrames, mTmpInsets);
-        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
+        final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+        final DisplayPolicy.DecorInsets.Info info = policy.getDecorInsetsInfo(
+                displayInfo.rotation, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, info.mNonDecorInsets);
+        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, info.mConfigInsets);
     }
 
     /**
@@ -2280,19 +2275,33 @@
 
         super.onConfigurationChanged(newParentConfig);
 
-        if (shouldStartChangeTransition(mTmpPrevBounds)) {
+        final boolean shouldStartChangeTransition = shouldStartChangeTransition(mTmpPrevBounds);
+        if (shouldStartChangeTransition) {
             initializeChangeTransition(mTmpPrevBounds);
-        } else if (mTaskFragmentOrganizer != null) {
-            // Update the surface here instead of in the organizer so that we can make sure
-            // it can be synced with the surface freezer.
-            final SurfaceControl.Transaction t = getSyncTransaction();
-            updateSurfacePosition(t);
-            updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+        }
+        if (mTaskFragmentOrganizer != null) {
+            if (mTransitionController.isShellTransitionsEnabled()
+                    && !mTransitionController.isCollecting(this)) {
+                // TaskFragmentOrganizer doesn't have access to the surface for security reasons, so
+                // update the surface here if it is not collected by Shell transition.
+                updateOrganizedTaskFragmentSurface();
+            } else if (!mTransitionController.isShellTransitionsEnabled()
+                    && !shouldStartChangeTransition) {
+                // Update the surface here instead of in the organizer so that we can make sure
+                // it can be synced with the surface freezer for legacy app transition.
+                updateOrganizedTaskFragmentSurface();
+            }
         }
 
         sendTaskFragmentInfoChanged();
     }
 
+    private void updateOrganizedTaskFragmentSurface() {
+        final SurfaceControl.Transaction t = getSyncTransaction();
+        updateSurfacePosition(t);
+        updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+    }
+
     /** Updates the surface size so that the sub windows cannot be shown out of bounds. */
     private void updateOrganizedTaskFragmentSurfaceSize(SurfaceControl.Transaction t,
             boolean forceUpdate) {
@@ -2347,33 +2356,16 @@
                 || endBounds.height() != startBounds.height();
     }
 
-    boolean canHaveEmbeddingActivityTransition(@NonNull ActivityRecord child) {
-        if (!isOrganizedTaskFragment() || !mTransitionController.isShellTransitionsEnabled()) {
-            return false;
-        }
-        // The activity should request open transition when it is becoming visible.
-        return child.isVisibleRequested();
-    }
-
-    void collectEmbeddedTaskFragmentIfNeeded() {
-        if (!isOrganizedTaskFragment() || mTransitionController.isCollecting(this)) {
-            return;
-        }
-        if (getChildCount() == 0) {
-            // The TaskFragment is new created, and just becoming non-empty.
-            mTransitionController.collectExistenceChange(this);
-        } else {
-            mTransitionController.collect(this);
-        }
+    @Override
+    boolean isSyncFinished() {
+        return super.isSyncFinished() && isReadyToTransit();
     }
 
     @Override
     void setSurfaceControl(SurfaceControl sc) {
         super.setSurfaceControl(sc);
         if (mTaskFragmentOrganizer != null) {
-            final SurfaceControl.Transaction t = getSyncTransaction();
-            updateSurfacePosition(t);
-            updateOrganizedTaskFragmentSurfaceSize(t, false /* forceUpdate */);
+            updateOrganizedTaskFragmentSurface();
             // If the TaskFragmentOrganizer was set before we created the SurfaceControl, we need to
             // emit the callbacks now.
             sendTaskFragmentAppeared();
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index d8a054c..8c037a7 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -45,6 +45,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.RemoteAnimationDefinition;
+import android.view.WindowManager;
 import android.window.ITaskFragmentOrganizer;
 import android.window.ITaskFragmentOrganizerController;
 import android.window.TaskFragmentInfo;
@@ -484,16 +485,31 @@
     }
 
     @Override
-    public void onTransactionHandled(@NonNull ITaskFragmentOrganizer organizer,
-            @NonNull IBinder transactionToken, @NonNull WindowContainerTransaction wct) {
+    public void onTransactionHandled(@NonNull IBinder transactionToken,
+            @NonNull WindowContainerTransaction wct,
+            @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
+        // Keep the calling identity to avoid unsecure change.
         synchronized (mGlobalLock) {
-            // Keep the calling identity to avoid unsecure change.
-            mWindowOrganizerController.applyTransaction(wct);
-            final TaskFragmentOrganizerState state = validateAndGetState(organizer);
+            applyTransaction(wct, transitionType, shouldApplyIndependently);
+            final TaskFragmentOrganizerState state = validateAndGetState(
+                    wct.getTaskFragmentOrganizer());
             state.onTransactionFinished(transactionToken);
         }
     }
 
+    @Override
+    public void applyTransaction(@NonNull WindowContainerTransaction wct,
+            @WindowManager.TransitionType int transitionType, boolean shouldApplyIndependently) {
+        // Keep the calling identity to avoid unsecure change.
+        synchronized (mGlobalLock) {
+            if (wct.isEmpty()) {
+                return;
+            }
+            mWindowOrganizerController.applyTaskFragmentTransactionLocked(wct, transitionType,
+                    shouldApplyIndependently);
+        }
+    }
+
     /**
      * Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
      * {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode.
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index b8d2feb..09fd900 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -53,6 +53,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -424,7 +425,7 @@
 
     private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
         if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: persistentTaskIds=" + persistentTaskIds +
-                " files=" + files);
+                " files=" + Arrays.toString(files));
         if (files == null) {
             Slog.e(TAG, "File error accessing recents directory (directory doesn't exist?).");
             return;
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index c7e39ce..32b7532 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -73,6 +73,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.Display;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.RemoteTransition;
@@ -84,11 +85,13 @@
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.inputmethod.InputMethodManagerInternal;
+import com.android.server.wm.utils.RotationAnimationUtils;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.Predicate;
 
 /**
@@ -280,9 +283,9 @@
         if (mContainerFreezer == null) {
             mContainerFreezer = new ScreenshotFreezer();
         }
-        mIsSeamlessRotation = true;
         final WindowState top = dc.getDisplayPolicy().getTopFullscreenOpaqueWindow();
         if (top != null) {
+            mIsSeamlessRotation = true;
             top.mSyncMethodOverride = BLASTSyncEngine.METHOD_BLAST;
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Override sync-method for %s "
                     + "because seamless rotating", top.getName());
@@ -566,17 +569,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);
@@ -698,7 +700,11 @@
                 // remove the surfaces yet. If it is currently visible, but not expected-visible,
                 // then doing commitVisibility here would actually be out-of-order and leave the
                 // activity in a bad state.
-                if (!visibleAtTransitionEnd && !ar.isVisibleRequested()) {
+                // TODO (b/243755838) Create a screen off transition to correct the visible status
+                // of activities.
+                final boolean isScreenOff = ar.mDisplayContent == null
+                        || ar.mDisplayContent.getDisplayInfo().state == Display.STATE_OFF;
+                if ((!visibleAtTransitionEnd || isScreenOff) && !ar.isVisibleRequested()) {
                     final boolean commitVisibility = !checkEnterPipOnFinish(ar);
                     // Avoid commit visibility if entering pip or else we will get a sudden
                     // "flash" / surface going invisible for a split second.
@@ -720,6 +726,10 @@
                 if (mChanges.get(ar).mVisible != visibleAtTransitionEnd) {
                     // Legacy dispatch relies on this (for now).
                     ar.mEnteringAnimation = visibleAtTransitionEnd;
+                } else if (mTransientLaunches != null && mTransientLaunches.containsKey(ar)
+                        && ar.isVisible()) {
+                    // Transient launch was committed, so report enteringAnimation
+                    ar.mEnteringAnimation = true;
                 }
                 continue;
             }
@@ -1595,6 +1605,9 @@
                 change.setEndAbsBounds(bounds);
             }
             change.setRotation(info.mRotation, endRotation);
+            if (info.mSnapshot != null) {
+                change.setSnapshot(info.mSnapshot, info.mSnapshotLuma);
+            }
 
             out.addChange(change);
         }
@@ -1750,6 +1763,10 @@
         /** These are just extra info. They aren't used for change-detection. */
         @Flag int mFlags = FLAG_NONE;
 
+        /** Snapshot surface and luma, if relevant. */
+        SurfaceControl mSnapshot;
+        float mSnapshotLuma;
+
         ChangeInfo(@NonNull WindowContainer origState) {
             mVisible = origState.isVisibleRequested();
             mWindowingMode = origState.getWindowingMode();
@@ -2058,8 +2075,8 @@
      */
     @VisibleForTesting
     private class ScreenshotFreezer implements IContainerFreezer {
-        /** Values are the screenshot "surfaces" or null if it was frozen via BLAST override. */
-        private final ArrayMap<WindowContainer, SurfaceControl> mSnapshots = new ArrayMap<>();
+        /** Keeps track of which windows are frozen. Not all frozen windows have snapshots. */
+        private final ArraySet<WindowContainer> mFrozen = new ArraySet<>();
 
         /** Takes a screenshot and puts it at the top of the container's surface. */
         @Override
@@ -2069,7 +2086,7 @@
             // Check if any parents have already been "frozen". If so, `wc` is already part of that
             // snapshot, so just skip it.
             for (WindowContainer p = wc; p != null; p = p.getParent()) {
-                if (mSnapshots.containsKey(p)) return false;
+                if (mFrozen.contains(p)) return false;
             }
 
             if (mIsSeamlessRotation) {
@@ -2078,7 +2095,7 @@
                 if (top != null && (top == wc || top.isDescendantOf(wc))) {
                     // Don't use screenshots for seamless windows: these will use BLAST even if not
                     // BLAST mode.
-                    mSnapshots.put(wc, null);
+                    mFrozen.add(wc);
                     return true;
                 }
             }
@@ -2103,15 +2120,26 @@
                 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())
                     .setCallsite("Transition.ScreenshotSync")
                     .setBLASTLayer()
                     .build();
-            mSnapshots.put(wc, snapshotSurface);
+            mFrozen.add(wc);
+            final ChangeInfo changeInfo = Objects.requireNonNull(mChanges.get(wc));
+            changeInfo.mSnapshot = snapshotSurface;
+            if (isDisplayRotation) {
+                // This isn't cheap, so only do it for display rotations.
+                changeInfo.mSnapshotLuma = RotationAnimationUtils.getMedianBorderLuma(
+                        screenshotBuffer.getHardwareBuffer(), screenshotBuffer.getColorSpace());
+            }
             SurfaceControl.Transaction t = wc.mWmService.mTransactionFactory.get();
 
             t.setBuffer(snapshotSurface, buffer);
@@ -2132,11 +2160,12 @@
 
         @Override
         public void cleanUp(SurfaceControl.Transaction t) {
-            for (int i = 0; i < mSnapshots.size(); ++i) {
-                SurfaceControl snap = mSnapshots.valueAt(i);
+            for (int i = 0; i < mFrozen.size(); ++i) {
+                SurfaceControl snap =
+                        Objects.requireNonNull(mChanges.get(mFrozen.valueAt(i))).mSnapshot;
                 // May be null if it was frozen via BLAST override.
                 if (snap == null) continue;
-                t.remove(snap);
+                t.reparent(snap, null /* newParent */);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 8269d96..221e186 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -227,6 +227,14 @@
     }
 
     /**
+     * @return the collecting transition. {@code null} if there is no collecting transition.
+     */
+    @Nullable
+    Transition getCollectingTransition() {
+        return mCollectingTransition;
+    }
+
+    /**
      * @return the collecting transition sync Id. This should only be called when there is a
      * collecting transition.
      */
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 6245005..d652b8e 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -19,6 +19,7 @@
 import static android.app.WallpaperManager.COMMAND_FREEZE;
 import static android.app.WallpaperManager.COMMAND_UNFREEZE;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
@@ -35,7 +36,9 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT;
 
+import android.annotation.Nullable;
 import android.graphics.Bitmap;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
@@ -45,6 +48,8 @@
 import android.util.ArraySet;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.view.animation.Animation;
@@ -56,6 +61,7 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 
 /**
@@ -113,8 +119,12 @@
      */
     private WindowState mTmpTopWallpaper;
 
+    @Nullable private Point mLargestDisplaySize = null;
+
     private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
 
+    private boolean mShouldOffsetWallpaperCenter;
+
     private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
         if ((w.mAttrs.type == TYPE_WALLPAPER)) {
             if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) {
@@ -241,6 +251,38 @@
         mDisplayContent = displayContent;
         mMaxWallpaperScale = service.mContext.getResources()
                 .getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale);
+        mShouldOffsetWallpaperCenter = service.mContext.getResources()
+                .getBoolean(
+                        com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay);
+    }
+
+    void resetLargestDisplay(Display display) {
+        if (display != null && display.getType() == Display.TYPE_INTERNAL) {
+            mLargestDisplaySize = null;
+        }
+    }
+
+    @VisibleForTesting void setShouldOffsetWallpaperCenter(boolean shouldOffset) {
+        mShouldOffsetWallpaperCenter = shouldOffset;
+    }
+
+    @Nullable private Point findLargestDisplaySize() {
+        if (!mShouldOffsetWallpaperCenter) {
+            return null;
+        }
+        Point largestDisplaySize = new Point();
+        List<DisplayInfo> possibleDisplayInfo =
+                mService.getPossibleDisplayInfoLocked(DEFAULT_DISPLAY);
+        for (int i = 0; i < possibleDisplayInfo.size(); i++) {
+            DisplayInfo displayInfo = possibleDisplayInfo.get(i);
+            if (displayInfo.type == Display.TYPE_INTERNAL
+                    && Math.max(displayInfo.logicalWidth, displayInfo.logicalHeight)
+                    > Math.max(largestDisplaySize.x, largestDisplaySize.y)) {
+                largestDisplaySize.set(displayInfo.logicalWidth,
+                        displayInfo.logicalHeight);
+            }
+        }
+        return largestDisplaySize;
     }
 
     WindowState getWallpaperTarget() {
@@ -327,24 +369,44 @@
     }
 
     boolean updateWallpaperOffset(WindowState wallpaperWin, boolean sync) {
-        final Rect bounds = wallpaperWin.getLastReportedBounds();
-        final int dw = bounds.width();
-        final int dh = bounds.height();
+        // Size of the display the wallpaper is rendered on.
+        final Rect lastWallpaperBounds = wallpaperWin.getLastReportedBounds();
+        // Full size of the wallpaper (usually larger than bounds above to parallax scroll when
+        // swiping through Launcher pages).
+        final Rect wallpaperFrame = wallpaperWin.getFrame();
 
-        int xOffset = 0;
-        int yOffset = 0;
+        int newXOffset = 0;
+        int newYOffset = 0;
         boolean rawChanged = false;
         // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
         // match the behavior of most Launchers
         float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
+        // "Wallpaper X" is the previous x-offset of the wallpaper (in a 0 to 1 scale).
+        // The 0 to 1 scale is because the "length" varies depending on how many home screens you
+        // have, so 0 is the left of the first home screen, and 1 is the right of the last one (for
+        // LTR, and the opposite for RTL).
         float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
+        // "Wallpaper X step size" is how much of that 0-1 is one "page" of the home screen
+        // when scrolling.
         float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
-        int availw = wallpaperWin.getFrame().right - wallpaperWin.getFrame().left - dw;
+        // Difference between width of wallpaper image, and the last size of the wallpaper.
+        // This is the horizontal surplus from the prior configuration.
+        int availw = wallpaperFrame.width() - lastWallpaperBounds.width();
+
+        int displayOffset = getDisplayWidthOffset(availw, lastWallpaperBounds,
+                wallpaperWin.isRtl());
+        availw -= displayOffset;
         int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
         if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+            // if device is LTR, then offset wallpaper to the left (the wallpaper is drawn
+            // always starting from the left of the screen).
             offset += mLastWallpaperDisplayOffsetX;
+        } else if (!wallpaperWin.isRtl()) {
+            // In RTL the offset is calculated so that the wallpaper ends up right aligned (see
+            // offset above).
+            offset -= displayOffset;
         }
-        xOffset = offset;
+        newXOffset = offset;
 
         if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
             wallpaperWin.mWallpaperX = wpx;
@@ -354,12 +416,13 @@
 
         float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
         float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
-        int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top - dh;
+        int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top
+                - lastWallpaperBounds.height();
         offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
         if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
             offset += mLastWallpaperDisplayOffsetY;
         }
-        yOffset = offset;
+        newYOffset = offset;
 
         if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
             wallpaperWin.mWallpaperY = wpy;
@@ -372,7 +435,7 @@
             rawChanged = true;
         }
 
-        boolean changed = wallpaperWin.setWallpaperOffset(xOffset, yOffset,
+        boolean changed = wallpaperWin.setWallpaperOffset(newXOffset, newYOffset,
                 wallpaperWin.mShouldScaleWallpaper
                         ? zoomOutToScale(wallpaperWin.mWallpaperZoomOut) : 1);
 
@@ -419,6 +482,52 @@
         return changed;
     }
 
+    /**
+     * Get an extra offset if needed ({@link #mShouldOffsetWallpaperCenter} = true, typically on
+     * multiple display devices) so that the wallpaper in a smaller display ends up centered at the
+     * same position as in the largest display of the device.
+     *
+     * Note that the wallpaper has already been cropped when set by the user, so these calculations
+     * apply to the image size for the display the wallpaper was set for.
+     *
+     * @param availWidth   width available for the wallpaper offset in the current display
+     * @param displayFrame size of the "display" (parent frame)
+     * @param isRtl        whether we're in an RTL configuration
+     * @return an offset to apply to the width, or 0 if the current configuration doesn't require
+     * any adjustment (either @link #mShouldOffsetWallpaperCenter} is false or we're on the largest
+     * display).
+     */
+    private int getDisplayWidthOffset(int availWidth, Rect displayFrame, boolean isRtl) {
+        if (!mShouldOffsetWallpaperCenter) {
+            return 0;
+        }
+        if (mLargestDisplaySize == null) {
+            mLargestDisplaySize = findLargestDisplaySize();
+        }
+        if (mLargestDisplaySize == null) {
+            return 0;
+        }
+        // Page width is the width of a Launcher "page", for pagination when swiping right.
+        int pageWidth = displayFrame.width();
+        // Only need offset if the current size is different from the largest display, and we're
+        // in a portrait configuration
+        if (mLargestDisplaySize.x != pageWidth && displayFrame.width() < displayFrame.height()) {
+            // The wallpaper will be scaled to fit the height of the wallpaper, so if the height
+            // of the displays are different, we need to account for that scaling when calculating
+            // the offset to the center
+            float sizeRatio = (float) displayFrame.height() / mLargestDisplaySize.y;
+            // Scale the width of the largest display to match the scale of the wallpaper size in
+            // the current display
+            int adjustedLargestWidth = Math.round(mLargestDisplaySize.x * sizeRatio);
+            // Finally, find the difference between the centers, taking into account that the
+            // size of the wallpaper frame could be smaller than the screen
+            return isRtl
+                    ? adjustedLargestWidth - (adjustedLargestWidth + pageWidth) / 2
+                    : Math.min(adjustedLargestWidth - pageWidth, availWidth) / 2;
+        }
+        return 0;
+    }
+
     void setWindowWallpaperPosition(
             WindowState window, float x, float y, float xStep, float yStep) {
         if (window.mWallpaperX != x || window.mWallpaperY != y)  {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d820ec4..bc66852 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1837,6 +1837,11 @@
         return null;
     }
 
+    int getDistanceFromTop(WindowContainer child) {
+        int idx = mChildren.indexOf(child);
+        return idx < 0 ? -1 : mChildren.size() - 1 - idx;
+    }
+
     private ActivityRecord processGetActivityWithBoundary(Predicate<ActivityRecord> callback,
             WindowContainer boundary, boolean includeBoundary, boolean traverseTopToBottom,
             boolean[] boundaryFound, WindowContainer wc) {
@@ -2831,7 +2836,6 @@
     void initializeChangeTransition(Rect startBounds, @Nullable SurfaceControl freezeTarget) {
         if (mDisplayContent.mTransitionController.isShellTransitionsEnabled()) {
             mDisplayContent.mTransitionController.collectVisibleChange(this);
-            // TODO(b/207070762): request shell transition for activityEmbedding change.
             return;
         }
         mDisplayContent.prepareAppTransition(TRANSIT_CHANGE);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8025cb2..5ad6fbd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -103,7 +103,6 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_KEEP_SCREEN_ON;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
@@ -218,7 +217,6 @@
 import android.os.SystemService;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.os.WorkSource;
 import android.provider.DeviceConfigInterface;
 import android.provider.Settings;
 import android.service.vr.IVrManager;
@@ -320,7 +318,6 @@
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.power.ShutdownThread;
 import com.android.server.utils.PriorityDump;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import dalvik.annotation.optimization.NeverCompile;
 
@@ -620,10 +617,6 @@
     boolean mBootAnimationStopped = false;
     long mBootWaitForWindowsStartTime = -1;
 
-    // Following variables are for debugging screen wakelock only.
-    WindowState mLastWakeLockHoldingWindow = null;
-    WindowState mLastWakeLockObscuringWindow = null;
-
     /** Dump of the windows and app tokens at the time of the last ANR. Cleared after
      * LAST_ANR_LIFETIME_DURATION_MSECS */
     String mLastANRState;
@@ -991,10 +984,6 @@
     private boolean mHasWideColorGamutSupport;
     private boolean mHasHdrSupport;
 
-    /** Who is holding the screen on. */
-    private Session mHoldingScreenOn;
-    private PowerManager.WakeLock mHoldingScreenWakeLock;
-
     /** Whether or not a layout can cause a wake up when theater mode is enabled. */
     boolean mAllowTheaterModeWakeFromLayout;
 
@@ -1326,10 +1315,6 @@
 
         mSettingsObserver = new SettingsObserver();
 
-        mHoldingScreenWakeLock = mPowerManager.newWakeLock(
-                PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM);
-        mHoldingScreenWakeLock.setReferenceCounted(false);
-
         mSurfaceAnimationRunner = new SurfaceAnimationRunner(mTransactionFactory,
                 mPowerManagerInternal);
 
@@ -1808,7 +1793,7 @@
                 prepareNoneTransitionForRelaunching(activity);
             }
 
-            if (displayPolicy.areSystemBarsForcedShownLw()) {
+            if (displayPolicy.areSystemBarsForcedConsumedLw()) {
                 res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_SYSTEM_BARS;
             }
 
@@ -1848,7 +1833,7 @@
                     + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
 
             if ((win.isVisibleRequestedOrAdding() && displayContent.updateOrientation())
-                    || win.providesNonDecorInsets()) {
+                    || displayPolicy.updateDecorInsetsInfoIfNeeded(win)) {
                 displayContent.sendNewConfiguration();
             }
 
@@ -2244,7 +2229,7 @@
             Arrays.fill(outActiveControls, null);
         }
         int result = 0;
-        boolean configChanged;
+        boolean configChanged = false;
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
@@ -2311,10 +2296,15 @@
                 flagChanges = win.mAttrs.flags ^ attrs.flags;
                 privateFlagChanges = win.mAttrs.privateFlags ^ attrs.privateFlags;
                 attrChanges = win.mAttrs.copyFrom(attrs);
-                if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
-                        | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
+                final boolean layoutChanged =
+                        (attrChanges & WindowManager.LayoutParams.LAYOUT_CHANGED) != 0;
+                if (layoutChanged || (attrChanges
+                        & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
                     win.mLayoutNeeded = true;
                 }
+                if (layoutChanged) {
+                    configChanged = displayPolicy.updateDecorInsetsInfoIfNeeded(win);
+                }
                 if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
                         || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
                     win.mActivityRecord.checkKeyguardFlagsChanged();
@@ -2518,7 +2508,7 @@
             }
 
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: updateOrientation");
-            configChanged = displayContent.updateOrientation();
+            configChanged |= displayContent.updateOrientation();
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
             if (toBeDisplayed && win.mIsWallpaper) {
@@ -2527,7 +2517,7 @@
             if (win.mActivityRecord != null) {
                 win.mActivityRecord.updateReportedVisibilityLocked();
             }
-            if (displayPolicy.areSystemBarsForcedShownLw()) {
+            if (displayPolicy.areSystemBarsForcedConsumedLw()) {
                 result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_SYSTEM_BARS;
             }
             if (!win.isGoneForLayout()) {
@@ -2556,7 +2546,7 @@
 
             if (outSyncIdBundle != null) {
                 final int maybeSyncSeqId;
-                if (USE_BLAST_SYNC && win.useBLASTSync() && viewVisibility != View.GONE
+                if (USE_BLAST_SYNC && win.useBLASTSync() && viewVisibility == View.VISIBLE
                         && win.mSyncSeqId > lastSyncSeqId) {
                     maybeSyncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1;
                     win.markRedrawForSyncReported();
@@ -3591,8 +3581,8 @@
             // Otherwise, we'll update it when it's prepared.
             if (mDisplayReady) {
                 final int forcedDensity = getForcedDisplayDensityForUserLocked(newUserId);
-                final int targetDensity = forcedDensity != 0 ? forcedDensity
-                        : displayContent.mInitialDisplayDensity;
+                final int targetDensity = forcedDensity != 0
+                        ? forcedDensity : displayContent.getInitialDisplayDensity();
                 displayContent.setForcedDensity(targetDensity, UserHandle.USER_CURRENT);
             }
         }
@@ -5803,7 +5793,7 @@
         synchronized (mGlobalLock) {
             final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
-                return displayContent.mInitialDisplayDensity;
+                return displayContent.getInitialDisplayDensity();
             }
         }
         return -1;
@@ -5858,7 +5848,7 @@
             synchronized (mGlobalLock) {
                 final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
-                    displayContent.setForcedDensity(displayContent.mInitialDisplayDensity,
+                    displayContent.setForcedDensity(displayContent.getInitialDisplayDensity(),
                             callingUserId);
                 }
             }
@@ -6013,34 +6003,6 @@
         });
     }
 
-    void setHoldScreenLocked(final Session newHoldScreen) {
-        final boolean hold = newHoldScreen != null;
-
-        if (hold && mHoldingScreenOn != newHoldScreen) {
-            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
-        }
-        mHoldingScreenOn = newHoldScreen;
-
-        final boolean state = mHoldingScreenWakeLock.isHeld();
-        if (hold != state) {
-            if (hold) {
-                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to %s",
-                            mRoot.mHoldScreenWindow);
-                mLastWakeLockHoldingWindow = mRoot.mHoldScreenWindow;
-                mLastWakeLockObscuringWindow = null;
-                mHoldingScreenWakeLock.acquire();
-                mPolicy.keepScreenOnStartedLw();
-            } else {
-                ProtoLog.d(WM_DEBUG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by %s",
-                            mRoot.mObscuringWindow);
-                mLastWakeLockHoldingWindow = null;
-                mLastWakeLockObscuringWindow = mRoot.mObscuringWindow;
-                mPolicy.keepScreenOnStoppedLw();
-                mHoldingScreenWakeLock.release();
-            }
-        }
-    }
-
     void requestTraversal() {
         mWindowPlacerLocked.requestTraversal();
     }
@@ -6674,9 +6636,6 @@
                     pw.print(mLastFinishedFreezeSource);
                 }
                 pw.println();
-        pw.print("  mLastWakeLockHoldingWindow=");pw.print(mLastWakeLockHoldingWindow);
-                pw.print(" mLastWakeLockObscuringWindow="); pw.print(mLastWakeLockObscuringWindow);
-                pw.println();
 
         mInputManagerCallback.dump(pw, "  ");
         mTaskSnapshotController.dump(pw, "  ");
@@ -7196,9 +7155,8 @@
         final DisplayContent dc = mRoot.getDisplayContent(displayId);
         if (dc != null) {
             final DisplayInfo di = dc.getDisplayInfo();
-            final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(di.rotation);
-            dc.getDisplayPolicy().getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
-                    cutout, outInsets);
+            outInsets.set(dc.getDisplayPolicy().getDecorInsetsInfo(
+                    di.rotation, di.logicalWidth, di.logicalHeight).mConfigInsets);
         }
     }
 
@@ -8896,7 +8854,7 @@
                             : overrideScale;
                     outInsetsState.scale(1f / compatScale);
                 }
-                return dc.getDisplayPolicy().areSystemBarsForcedShownLw();
+                return dc.getDisplayPolicy().areSystemBarsForcedConsumedLw();
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -8916,13 +8874,19 @@
                 }
 
                 // Retrieve the DisplayInfo across all possible display layouts.
-                return List.copyOf(mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId));
+                return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
+    List<DisplayInfo> getPossibleDisplayInfoLocked(int displayId) {
+        // Retrieve the DisplayInfo for all possible rotations across all possible display
+        // layouts.
+        return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId);
+    }
+
     /**
      * Returns {@code true} when the calling package is the recents component.
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index ff43a96..c22091b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -34,7 +34,6 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
@@ -47,8 +46,6 @@
 
 import com.android.internal.os.ByteTransferPipe;
 import com.android.internal.protolog.ProtoLogImpl;
-import com.android.server.LocalServices;
-import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
 import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
 import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
@@ -56,7 +53,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
@@ -106,19 +102,11 @@
                     // trace files can be written.
                     return mInternal.mWindowTracing.onShellCommand(this);
                 case "logging":
-                    String[] args = peekRemainingArgs();
                     int result = ProtoLogImpl.getSingleInstance().onShellCommand(this);
                     if (result != 0) {
-                        // Let the shell try and handle this
-                        try (ParcelFileDescriptor pfd
-                                     = ParcelFileDescriptor.dup(getOutFileDescriptor())){
-                            pw.println("Not handled, calling status bar with args: "
-                                    + Arrays.toString(args));
-                            LocalServices.getService(StatusBarManagerInternal.class)
-                                    .handleWindowManagerLoggingCommand(args, pfd);
-                        } catch (IOException e) {
-                            pw.println("Failed to handle logging command: " + e.getMessage());
-                        }
+                        pw.println("Not handled, please use "
+                                + "`adb shell dumpsys activity service SystemUIService WMShell` "
+                                + "if you are looking for ProtoLog in WMShell");
                     }
                     return result;
                 case "user-rotation":
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 34a4bf1..9456f0f 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -21,7 +21,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
 import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_RECT_INSETS_PROVIDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
@@ -29,6 +28,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_LAUNCH_TASK;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_PENDING_INTENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_INSETS_PROVIDER;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REPARENT_ACTIVITY_TO_TASK_FRAGMENT;
@@ -74,6 +74,7 @@
 import android.util.Slog;
 import android.view.RemoteAnimationAdapter;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 import android.window.IDisplayAreaOrganizerController;
 import android.window.ITaskFragmentOrganizer;
 import android.window.ITaskFragmentOrganizerController;
@@ -176,7 +177,7 @@
         if (t == null) {
             throw new IllegalArgumentException("Null transaction passed to applyTransaction");
         }
-        enforceTaskPermission("applyTransaction()", t);
+        enforceTaskPermission("applyTransaction()");
         final CallerInfo caller = new CallerInfo();
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -194,7 +195,7 @@
         if (t == null) {
             throw new IllegalArgumentException("Null transaction passed to applySyncTransaction");
         }
-        enforceTaskPermission("applySyncTransaction()", t);
+        enforceTaskPermission("applySyncTransaction()");
         final CallerInfo caller = new CallerInfo();
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -373,6 +374,89 @@
         }
     }
 
+    /**
+     * Applies the {@link WindowContainerTransaction} as a request from
+     * {@link android.window.TaskFragmentOrganizer}.
+     *
+     * @param wct   {@link WindowContainerTransaction} to apply.
+     * @param type  {@link WindowManager.TransitionType} if it needs to start a new transition.
+     * @param shouldApplyIndependently  If {@code true}, the {@code wct} will request a new
+     *                                  transition, which will be queued until the sync engine is
+     *                                  free if there is any other active sync. If {@code false},
+     *                                  the {@code wct} will be directly applied to the active sync.
+     */
+    void applyTaskFragmentTransactionLocked(@NonNull WindowContainerTransaction wct,
+            @WindowManager.TransitionType int type, boolean shouldApplyIndependently) {
+        if (!isValidTransaction(wct)) {
+            return;
+        }
+        enforceTaskFragmentOrganizerPermission("applyTaskFragmentTransaction()",
+                Objects.requireNonNull(wct.getTaskFragmentOrganizer()),
+                Objects.requireNonNull(wct));
+        final CallerInfo caller = new CallerInfo();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            if (mTransitionController.getTransitionPlayer() == null) {
+                // No need to worry about transition when Shell transition is not enabled.
+                applyTransaction(wct, -1 /* syncId */, null /* transition */, caller);
+                return;
+            }
+
+            if (!mService.mWindowManager.mSyncEngine.hasActiveSync()) {
+                // Sync is for either transition or applySyncTransaction(). We don't support
+                // multiple sync at the same time because it may cause conflict.
+                // Create a new transition when there is no active sync to collect the changes.
+                final Transition transition = mTransitionController.createTransition(type);
+                applyTransaction(wct, -1 /* syncId */, transition, caller);
+                mTransitionController.requestStartTransition(transition, null /* startTask */,
+                        null /* remoteTransition */, null /* displayChange */);
+                return;
+            }
+
+            if (!shouldApplyIndependently) {
+                // Although there is an active sync, we want to apply the transaction now.
+                // TODO(b/232042367) Redesign the organizer update on activity callback so that we
+                // we will know about the transition explicitly.
+                final Transition transition = mTransitionController.getCollectingTransition();
+                if (transition == null) {
+                    // This should rarely happen, and we should try to avoid using
+                    // {@link #applySyncTransaction} with Shell transition.
+                    // We still want to apply and merge the transaction to the active sync
+                    // because {@code shouldApplyIndependently} is {@code false}.
+                    ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                            "TaskFragmentTransaction changes are not collected in transition"
+                                    + " because there is an ongoing sync for"
+                                    + " applySyncTransaction().");
+                }
+                applyTransaction(wct, -1 /* syncId */, transition, caller);
+                return;
+            }
+
+            // It is ok to queue the WCT until the sync engine is free.
+            final Transition nextTransition = new Transition(type, 0 /* flags */,
+                    mTransitionController, mService.mWindowManager.mSyncEngine);
+            ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
+                    "Creating Pending Transition for TaskFragment: %s", nextTransition);
+            mService.mWindowManager.mSyncEngine.queueSyncSet(
+                    // Make sure to collect immediately to prevent another transition
+                    // from sneaking in before it. Note: moveToCollecting internally
+                    // calls startSyncSet.
+                    () -> mTransitionController.moveToCollecting(nextTransition),
+                    () -> {
+                        if (isValidTransaction(wct)) {
+                            applyTransaction(wct, -1 /*syncId*/, nextTransition, caller);
+                            mTransitionController.requestStartTransition(nextTransition,
+                                    null /* startTask */, null /* remoteTransition */,
+                                    null /* displayChange */);
+                        } else {
+                            nextTransition.abort();
+                        }
+                    });
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
     private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
             @Nullable Transition transition, @NonNull CallerInfo caller) {
         applyTransaction(t, syncId, transition, caller, null /* finishTransition */);
@@ -387,12 +471,6 @@
     private void applyTransaction(@NonNull WindowContainerTransaction t, int syncId,
             @Nullable Transition transition, @NonNull CallerInfo caller,
             @Nullable Transition finishTransition) {
-        if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController
-                .isOrganizerRegistered(t.getTaskFragmentOrganizer())) {
-            Slog.e(TAG, "Caller organizer=" + t.getTaskFragmentOrganizer()
-                    + " is no longer registered");
-            return;
-        }
         int effects = 0;
         ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Apply window transaction, syncId=%d", syncId);
         mService.deferWindowLayout();
@@ -703,6 +781,12 @@
             @Nullable ITaskFragmentOrganizer organizer, @Nullable Transition finishTransition) {
         final int type = hop.getType();
         switch (type) {
+            case HIERARCHY_OP_TYPE_REMOVE_TASK: {
+                final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
+                final Task task = wc != null ? wc.asTask() : null;
+                task.remove(true, "Applying remove task Hierarchy Op");
+                break;
+            }
             case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
                 final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
                 final Task task = wc != null ? wc.asTask() : null;
@@ -738,7 +822,8 @@
             case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
                 final TaskFragmentCreationParams taskFragmentCreationOptions =
                         hop.getTaskFragmentCreationOptions();
-                createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller);
+                createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller,
+                        transition);
                 break;
             }
             case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
@@ -765,7 +850,8 @@
                         break;
                     }
                 }
-                effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken);
+                effects |= deleteTaskFragment(taskFragment, organizer, errorCallbackToken,
+                        transition);
                 break;
             }
             case HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT: {
@@ -839,8 +925,15 @@
                     break;
                 }
 
-                prepareActivityEmbeddingTransitionForReparentActivityToTaskFragment(parent,
-                        activity);
+                if (transition != null) {
+                    transition.collect(activity);
+                    if (activity.getParent() != null) {
+                        // Collect the current parent. Its visibility may change as a result of
+                        // this reparenting.
+                        transition.collect(activity.getParent());
+                    }
+                    transition.collect(parent);
+                }
                 activity.reparent(parent, POSITION_TOP);
                 effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
@@ -1035,7 +1128,7 @@
                     break;
                 }
                 reparentTaskFragment(oldParent.asTaskFragment(), newParent, organizer,
-                        errorCallbackToken);
+                        errorCallbackToken, transition);
                 effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
             }
@@ -1079,41 +1172,6 @@
         return effects;
     }
 
-    private void prepareActivityEmbeddingTransitionForReparentActivityToTaskFragment(
-            @NonNull TaskFragment taskFragment, @NonNull ActivityRecord activity) {
-        if (!taskFragment.canHaveEmbeddingActivityTransition(activity)) {
-            return;
-        }
-
-        // The reparent can happen in the following cases:
-        // 1. Reparent an existing activity to split when app launches new intent.
-        //    - This happens after app calls to start activity, but before the activity is actually
-        //      started, so we don't expect any collecting transition, but if it does, we can't
-        //      queue the WCT because the start activity won't wait.
-        // 2. Reparent an existing activity to split to launch placeholder when Task size changed.
-        //    - We expect to have a collecting transition for the Task resize, so just collect.
-        // 3. Reparent a new launching activity to an always-expand container.
-        // 4. Reparent a new launching activity to split to launch placeholder together.
-        // 5. Reparent a new launching activity to an existing split.
-        //    - The new launching activity should have start an OPEN transition, so just collect.
-        // 6. Reparent PiP activity back to the original Task.
-        //    - This should be part of the exiting PiP transition, so just collect.
-
-        if (!taskFragment.getBounds().equals(activity.getBounds()) && activity.isVisible()
-                && !mTransitionController.isCollecting()) {
-            // 1. Reparent an existing activity to split when app launches new intent.
-            mTransitionController.requestTransitionIfNeeded(TRANSIT_CHANGE, activity);
-        }
-
-        // We expect the activity to be in the transition already, so just collect the TaskFragment.
-        if (mTransitionController.isCollecting(activity)) {
-            taskFragment.collectEmbeddedTaskFragmentIfNeeded();
-        } else {
-            ProtoLog.w(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS, "Reparenting Activity"
-                    + " to embedded TaskFragment, but the Activity is not collected");
-        }
-    }
-
     /** A helper method to send minimum dimension violation error to the client. */
     private void sendMinimumDimensionViolation(TaskFragment taskFragment, Point minDimensions,
             IBinder errorCallbackToken, String reason) {
@@ -1488,25 +1546,24 @@
         mService.enforceTaskPermission(func);
     }
 
-    private void enforceTaskPermission(String func, @Nullable WindowContainerTransaction t) {
-        if (t == null || t.getTaskFragmentOrganizer() == null) {
-            enforceTaskPermission(func);
-            return;
+    private boolean isValidTransaction(@NonNull WindowContainerTransaction t) {
+        if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController
+                .isOrganizerRegistered(t.getTaskFragmentOrganizer())) {
+            // Transaction from an unregistered organizer should not be applied. This can happen
+            // when the organizer process died before the transaction is applied.
+            Slog.e(TAG, "Caller organizer=" + t.getTaskFragmentOrganizer()
+                    + " is no longer registered");
+            return false;
         }
-
-        // Apps may not have the permission to manage Tasks, but we are allowing apps to manage
-        // TaskFragments belonging to their own Task.
-        enforceOperationsAllowedForTaskFragmentOrganizer(func, t);
+        return true;
     }
 
     /**
      * Makes sure that the transaction only contains operations that are allowed for the
      * {@link WindowContainerTransaction#getTaskFragmentOrganizer()}.
      */
-    private void enforceOperationsAllowedForTaskFragmentOrganizer(
-            String func, WindowContainerTransaction t) {
-        final ITaskFragmentOrganizer organizer = t.getTaskFragmentOrganizer();
-
+    private void enforceTaskFragmentOrganizerPermission(@NonNull String func,
+            @NonNull ITaskFragmentOrganizer organizer, @NonNull WindowContainerTransaction t) {
         // Configuration changes
         final Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
                 t.getChanges().entrySet().iterator();
@@ -1691,8 +1748,9 @@
         }
     }
 
-    void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
-            @Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller) {
+    private void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
+            @Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller,
+            @Nullable Transition transition) {
         final ActivityRecord ownerActivity =
                 ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
         final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
@@ -1747,11 +1805,13 @@
         taskFragment.setWindowingMode(creationParams.getWindowingMode());
         taskFragment.setBounds(creationParams.getInitialBounds());
         mLaunchTaskFragments.put(creationParams.getFragmentToken(), taskFragment);
+
+        if (transition != null) transition.collectExistenceChange(taskFragment);
     }
 
-    void reparentTaskFragment(@NonNull TaskFragment oldParent,
+    private void reparentTaskFragment(@NonNull TaskFragment oldParent,
             @Nullable WindowContainer<?> newParent, @Nullable ITaskFragmentOrganizer organizer,
-            @Nullable IBinder errorCallbackToken) {
+            @Nullable IBinder errorCallbackToken, @Nullable Transition transition) {
         final TaskFragment newParentTF;
         if (newParent == null) {
             // Use the old parent's parent if the caller doesn't specify the new parent.
@@ -1793,13 +1853,24 @@
                     HIERARCHY_OP_TYPE_REPARENT_CHILDREN, exception);
             return;
         }
+        if (transition != null) {
+            // Collect the current parent. It's visibility may change as a result of this
+            // reparenting.
+            transition.collect(oldParent);
+            transition.collect(newParentTF);
+        }
         while (oldParent.hasChild()) {
-            oldParent.getChildAt(0).reparent(newParentTF, POSITION_TOP);
+            final WindowContainer child = oldParent.getChildAt(0);
+            if (transition != null) {
+                transition.collect(child);
+            }
+            child.reparent(newParentTF, POSITION_TOP);
         }
     }
 
     private int deleteTaskFragment(@NonNull TaskFragment taskFragment,
-            @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken) {
+            @Nullable ITaskFragmentOrganizer organizer, @Nullable IBinder errorCallbackToken,
+            @Nullable Transition transition) {
         final int index = mLaunchTaskFragments.indexOfValue(taskFragment);
         if (index < 0) {
             final Throwable exception =
@@ -1819,6 +1890,9 @@
                     HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT, exception);
             return 0;
         }
+
+        if (transition != null) transition.collectExistenceChange(taskFragment);
+
         mLaunchTaskFragments.removeAt(index);
         taskFragment.remove(true /* withTransition */, "deleteTaskFragment");
         return TRANSACT_EFFECTS_LIFECYCLE;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3469303..df7b8bb 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2510,6 +2510,7 @@
                     mWinAnimator.mSurfaceController,
                     Debug.getCallers(5));
 
+        final DisplayContent displayContent = getDisplayContent();
         final long origId = Binder.clearCallingIdentity();
 
         try {
@@ -2564,7 +2565,7 @@
                     // Set up a replacement input channel since the app is now dead.
                     // We need to catch tapping on the dead window to restart the app.
                     openInputChannel(null);
-                    getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/);
+                    displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
                     return;
                 }
 
@@ -2572,7 +2573,7 @@
                 // usually unnoticeable (e.g. covered by rotation animation) and the animation
                 // bounds could be inconsistent, such as depending on when the window applies
                 // its draw transaction with new rotation.
-                final boolean allowExitAnimation = !getDisplayContent().inTransition()
+                final boolean allowExitAnimation = !displayContent.inTransition()
                         // There will be a new window so the exit animation may not be visible or
                         // look weird if its orientation is changed.
                         && !inRelaunchingActivity();
@@ -2622,18 +2623,11 @@
             }
 
             removeImmediately();
-            boolean sentNewConfig = false;
-            if (wasVisible) {
-                // Removing a visible window will effect the computed orientation
-                // So just update orientation if needed.
-                final DisplayContent displayContent = getDisplayContent();
-                if (displayContent.updateOrientation()) {
-                    displayContent.sendNewConfiguration();
-                    sentNewConfig = true;
-                }
-            }
-            if (!sentNewConfig && providesNonDecorInsets()) {
-                getDisplayContent().sendNewConfiguration();
+            // Removing a visible window may affect the display orientation so just update it if
+            // needed. Also recompute configuration if it provides screen decor insets.
+            if ((wasVisible && displayContent.updateOrientation())
+                    || displayContent.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(this)) {
+                displayContent.sendNewConfiguration();
             }
             mWmService.updateFocusedWindowLocked(isFocused()
                             ? UPDATE_FOCUS_REMOVING_FOCUS
@@ -3917,7 +3911,7 @@
         final boolean forceRelayout = syncWithBuffers || isDragResizeChanged;
         final DisplayContent displayContent = getDisplayContent();
         final boolean alwaysConsumeSystemBars =
-                displayContent.getDisplayPolicy().areSystemBarsForcedShownLw();
+                displayContent.getDisplayPolicy().areSystemBarsForcedConsumedLw();
         final int displayId = displayContent.getDisplayId();
 
         if (isDragResizeChanged) {
@@ -5953,10 +5947,10 @@
 
     @Override
     boolean isSyncFinished() {
-        if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility == View.GONE
+        if (mSyncState == SYNC_STATE_WAITING_FOR_DRAW && mViewVisibility != View.VISIBLE
                 && !isVisibleRequested()) {
-            // Don't wait for GONE windows. However, we don't alter the state in case the window
-            // becomes un-gone while the syncset is still active.
+            // Don't wait for invisible windows. However, we don't alter the state in case the
+            // window becomes visible while the sync group is still active.
             return true;
         }
         return super.isSyncFinished();
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 2ee5fb0..aa58902 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -228,7 +228,5 @@
 
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
-        pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
-        pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow);
     }
 }
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 4078996..5d6ffd8 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -37,6 +37,7 @@
         "com_android_server_ConsumerIrService.cpp",
         "com_android_server_companion_virtual_InputController.cpp",
         "com_android_server_devicepolicy_CryptoTestHelper.cpp",
+        "com_android_server_display_DisplayControl.cpp",
         "com_android_server_connectivity_Vpn.cpp",
         "com_android_server_gpu_GpuService.cpp",
         "com_android_server_HardwarePropertiesManagerService.cpp",
@@ -89,6 +90,7 @@
 
 cc_defaults {
     name: "libservices.core-libs",
+    defaults: ["android.hardware.graphics.common-ndk_shared"],
     shared_libs: [
         "libadb_pairing_server",
         "libadb_pairing_connection",
@@ -158,7 +160,6 @@
         "[email protected]",
         "[email protected]",
         "[email protected]",
-        "android.hardware.graphics.common-V3-ndk",
         "[email protected]",
         "android.hardware.input.processor-V1-ndk",
         "[email protected]",
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_display_DisplayControl.cpp b/services/core/jni/com_android_server_display_DisplayControl.cpp
new file mode 100644
index 0000000..61f2b14
--- /dev/null
+++ b/services/core/jni/com_android_server_display_DisplayControl.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 <android_util_Binder.h>
+#include <gui/SurfaceComposerClient.h>
+#include <jni.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+namespace android {
+
+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 const JNINativeMethod sDisplayMethods[] = {
+        // clang-format off
+    {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
+            (void*)nativeCreateDisplay },
+    {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
+            (void*)nativeDestroyDisplay },
+        // clang-format on
+};
+
+int register_com_android_server_display_DisplayControl(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "com/android/server/display/DisplayControl",
+                                    sDisplayMethods, NELEM(sDisplayMethods));
+}
+
+} // namespace android
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 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/jni/onload.cpp b/services/core/jni/onload.cpp
index 0cd9494..00bef09 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -64,6 +64,7 @@
 int register_android_server_companion_virtual_InputController(JNIEnv* env);
 int register_android_server_app_GameManagerService(JNIEnv* env);
 int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
+int register_com_android_server_display_DisplayControl(JNIEnv* env);
 };
 
 using namespace android;
@@ -120,5 +121,6 @@
     register_android_server_companion_virtual_InputController(env);
     register_android_server_app_GameManagerService(env);
     register_com_android_server_wm_TaskFpsCallbackController(env);
+    register_com_android_server_display_DisplayControl(env);
     return JNI_VERSION_1_4;
 }
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 98f83d8..6b05d8f 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -406,7 +406,7 @@
             <!-- Desired screen brightness in nits corresponding to the suggested lux values.
              The display brightness is defined as the measured brightness of an all-white image.
              This must be a non-negative integer -->
-            <xs:element name="nits" type="xs:nonNegativeInteger"
+            <xs:element name="nits" type="nonNegativeDecimal"
                         minOccurs="1" maxOccurs="1">
                 <xs:annotation name="final"/>
             </xs:element>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index e5d2617..fb7a920 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -53,9 +53,9 @@
   public class DisplayBrightnessPoint {
     ctor public DisplayBrightnessPoint();
     method public final java.math.BigInteger getLux();
-    method public final java.math.BigInteger getNits();
+    method public final java.math.BigDecimal getNits();
     method public final void setLux(java.math.BigInteger);
-    method public final void setNits(java.math.BigInteger);
+    method public final void setNits(java.math.BigDecimal);
   }
 
   public class DisplayConfiguration {
diff --git a/services/credentials/Android.bp b/services/credentials/Android.bp
new file mode 100644
index 0000000..5fa4442
--- /dev/null
+++ b/services/credentials/Android.bp
@@ -0,0 +1,22 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+filegroup {
+    name: "services.credentials-sources",
+    srcs: ["java/**/*.java"],
+    path: "java",
+    visibility: ["//frameworks/base/services"],
+}
+
+java_library_static {
+    name: "services.credentials",
+    defaults: ["platform_service_defaults"],
+    srcs: [":services.credentials-sources"],
+    libs: ["services.core"],
+}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
new file mode 100644
index 0000000..76ed2b3
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.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.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.credentials.ICredentialManager;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.SecureSettingsServiceNameResolver;
+
+/**
+ * Entry point service for credential management.
+ *
+ * <p>This service provides the {@link ICredentialManager} implementation and keeps a list of
+ * {@link CredentialManagerServiceImpl} per user; the real work is done by
+ * {@link CredentialManagerServiceImpl} itself.
+ */
+public final class CredentialManagerService extends
+        AbstractMasterSystemService<CredentialManagerService, CredentialManagerServiceImpl> {
+
+    private static final String TAG = "CredManSysService";
+
+    public CredentialManagerService(@NonNull Context context) {
+        super(context,
+                new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
+                null, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+    }
+
+    @Override
+    protected String getServiceSettingsProperty() {
+        return Settings.Secure.AUTOFILL_SERVICE;
+    }
+
+    @Override // from AbstractMasterSystemService
+    protected CredentialManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
+            boolean disabled) {
+        return new CredentialManagerServiceImpl(this, mLock, resolvedUserId);
+    }
+
+    @Override
+    public void onStart() {
+        Log.i(TAG, "onStart");
+    }
+
+    final class CredentialManagerServiceStub extends ICredentialManager.Stub {
+        @Override
+        public void getCredential() {
+            final int userId = UserHandle.getCallingUserId();
+            synchronized (mLock) {
+                final CredentialManagerServiceImpl service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    Log.i(TAG, "Got service for : " + userId);
+                    service.getCredential();
+                }
+            }
+        }
+    }
+}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
new file mode 100644
index 0000000..f45f626
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerServiceImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.credentials;
+
+import android.annotation.NonNull;
+import android.util.Log;
+
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/**
+ * Per-user implementation of {@link CredentialManagerService}
+ */
+public class CredentialManagerServiceImpl extends
+        AbstractPerUserSystemService<CredentialManagerServiceImpl, CredentialManagerService> {
+    private static final String TAG = "CredManSysServiceImpl";
+
+    protected CredentialManagerServiceImpl(
+            @NonNull CredentialManagerService master,
+            @NonNull Object lock, int userId) {
+        super(master, lock, userId);
+    }
+
+    /**
+     * Unimplemented getCredentials
+     */
+    public void getCredential() {
+        Log.i(TAG, "getCredential not implemented");
+        // TODO : Implement logic
+    }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index fbaf1ce..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;
@@ -671,6 +671,15 @@
     @EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
     private static final long PREVENT_SETTING_PASSWORD_QUALITY_ON_PARENT = 165573442L;
 
+    /**
+     * For Admin Apps targeting U+
+     * If {@link android.security.IKeyChainService#setGrant} is called with an alias with no
+     * existing key, throw IllegalArgumentException.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    private static final long THROW_EXCEPTION_WHEN_KEY_MISSING = 175101461L;
+
     private static final String CREDENTIAL_MANAGEMENT_APP_INVALID_ALIAS_MSG =
             "The alias provided must be contained in the aliases specified in the credential "
                     + "management app's authentication policy";
@@ -5654,8 +5663,16 @@
 
         final CallerIdentity caller = getCallerIdentity(callerPackage);
         Preconditions.checkCallAuthorization(canChooseCertificates(caller));
-
-        return setKeyChainGrantInternal(alias, hasGrant, Process.WIFI_UID, caller.getUserHandle());
+        try {
+            return setKeyChainGrantInternal(
+                    alias, hasGrant, Process.WIFI_UID, caller.getUserHandle());
+        } catch (IllegalArgumentException e) {
+            if (mInjector.isChangeEnabled(THROW_EXCEPTION_WHEN_KEY_MISSING, caller.getPackageName(),
+                    caller.getUserId())) {
+                throw e;
+            }
+            return false;
+        }
     }
 
     @Override
@@ -5705,8 +5722,15 @@
         } catch (RemoteException e) {
             throw new IllegalStateException("Failure getting grantee uid", e);
         }
-
-        return setKeyChainGrantInternal(alias, hasGrant, granteeUid, caller.getUserHandle());
+        try {
+            return setKeyChainGrantInternal(alias, hasGrant, granteeUid, caller.getUserHandle());
+        } catch (IllegalArgumentException e) {
+            if (mInjector.isChangeEnabled(THROW_EXCEPTION_WHEN_KEY_MISSING, packageName,
+                    caller.getUserId())) {
+                throw e;
+            }
+            return false;
+        }
     }
 
     private boolean setKeyChainGrantInternal(String alias, boolean hasGrant, int granteeUid,
@@ -5760,36 +5784,6 @@
         return new ParcelableGranteeMap(result);
     }
 
-    /**
-     * Enforce one the following conditions are met:
-     * (1) The device has a Device Owner, and one of the following holds:
-     *   (1.1) The caller is the Device Owner
-     *   (1.2) The caller is another app in the same user as the device owner, AND
-     *         The caller is the delegated certificate installer.
-     *   (1.3) The caller is a Profile Owner and the calling user is affiliated.
-     * (2) The user has a profile owner, AND:
-     *   (2.1) The profile owner has been granted access to Device IDs and one of the following
-     *         holds:
-     *     (2.1.1) The caller is the profile owner.
-     *     (2.1.2) The caller is from another app in the same user as the profile owner, AND
-     *       (2.1.2.1) The caller is the delegated cert installer.
-     *
-     *  For the device owner case, simply check that the caller is the device owner or the
-     *  delegated certificate installer.
-     *
-     *  For the profile owner case, first check that the caller is the profile owner or can
-     *  manage the DELEGATION_CERT_INSTALL scope.
-     *  If that check succeeds, ensure the profile owner was granted access to device
-     *  identifiers. The grant is transitive: The delegated cert installer is implicitly allowed
-     *  access to device identifiers in this case as part of the delegation.
-     */
-    @VisibleForTesting
-    public void enforceCallerCanRequestDeviceIdAttestation(CallerIdentity caller)
-            throws SecurityException {
-        Preconditions.checkCallAuthorization(hasDeviceIdAccessUnchecked(caller.getPackageName(),
-                caller.getUid()));
-    }
-
     @VisibleForTesting
     public static int[] translateIdAttestationFlags(
             int idAttestationFlags) {
@@ -5844,8 +5838,8 @@
         final boolean isCallerDelegate = isCallerDelegate(caller, DELEGATION_CERT_INSTALL);
         final boolean isCredentialManagementApp = isCredentialManagementApp(caller);
         if (deviceIdAttestationRequired && attestationUtilsFlags.length > 0) {
-            // TODO: replace enforce methods
-            enforceCallerCanRequestDeviceIdAttestation(caller);
+            Preconditions.checkCallAuthorization(hasDeviceIdAccessUnchecked(
+                    caller.getPackageName(), caller.getUid()));
             enforceIndividualAttestationSupportedIfRequested(attestationUtilsFlags);
         } else {
             Preconditions.checkCallAuthorization((caller.hasAdminComponent()
@@ -8342,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)
@@ -8800,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);
@@ -9376,21 +9368,36 @@
     }
 
     /**
-     * Check if caller is device owner, delegate cert installer or profile owner of
-     * affiliated user. Or if caller is profile owner for a specified user or delegate cert
-     * installer on an organization-owned device.
+     * Check if one the following conditions hold:
+     * (1) The device has a Device Owner, and one of the following holds:
+     *   (1.1) The caller is the Device Owner
+     *   (1.2) The caller is another app in the same user as the device owner, AND
+     *         The caller is the delegated certificate installer.
+     *   (1.3) The caller is a Profile Owner and the calling user is affiliated.
+     * (2) The user has a profile owner, AND:
+     *   (2.1) The profile owner has been granted access to Device IDs and one of the following
+     *         holds:
+     *     (2.1.1) The caller is the profile owner.
+     *     (2.1.2) The caller is from another app in the same user as the profile owner, AND
+     *             the caller is the delegated cert installer.
+     *
+     *  For the device owner case, simply check that the caller is the device owner or the
+     *  delegated certificate installer.
+     *
+     *  For the profile owner case, first check that the caller is the profile owner or can
+     *  manage the DELEGATION_CERT_INSTALL scope.
+     *  If that check succeeds, ensure the profile owner was granted access to device
+     *  identifiers. The grant is transitive: The delegated cert installer is implicitly allowed
+     *  access to device identifiers in this case as part of the delegation.
      */
-    private boolean hasDeviceIdAccessUnchecked(String packageName, int uid) {
-        // Is the caller a  device owner, delegate cert installer or profile owner of an
-        // affiliated user.
+    @VisibleForTesting
+    boolean hasDeviceIdAccessUnchecked(String packageName, int uid) {
         ComponentName deviceOwner = getDeviceOwnerComponent(true);
         if (deviceOwner != null && (deviceOwner.getPackageName().equals(packageName)
                 || isCallerDelegate(packageName, uid, DELEGATION_CERT_INSTALL))) {
             return true;
         }
         final int userId = UserHandle.getUserId(uid);
-        // Is the caller the profile owner for the specified user, or delegate cert installer on an
-        // organization-owned device.
         ComponentName profileOwner = getProfileOwnerAsUser(userId);
         final boolean isCallerProfileOwnerOrDelegate = profileOwner != null
                 && (profileOwner.getPackageName().equals(packageName)
@@ -10213,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);
@@ -10808,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);
@@ -14696,12 +14706,6 @@
             if (parentUser == null) {
                 throw new IllegalStateException(String.format("User %d is not a profile", userId));
             }
-            if (!parentUser.isSystem()) {
-                throw new IllegalStateException(
-                        String.format("Only the profile owner of a managed profile on the"
-                                + " primary user can be granted access to device identifiers, not"
-                                + " on user %d", parentUser.getIdentifier()));
-            }
 
             mUserManager.setUserRestriction(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE,
                     isProfileOwnerOnOrganizationOwnedDevice,
@@ -15409,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 {
@@ -15436,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();
@@ -17655,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.");
@@ -17845,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(
@@ -18045,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();
@@ -18176,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;
@@ -18703,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/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 2f031bf..45ca5cd 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -216,7 +216,10 @@
     if (!content) {
         return {};
     }
-    return {content->data(), (int)content->size()};
+    // TODO(b/175635923): Replace with {content->data(), content->size()} after libc++ is upgraded.
+    // The type of the second std::span ctor param changed from ptrdiff_t to size_t between the old
+    // libc++ and the finalized C++20.
+    return std::span<const uint8_t>(content->data(), content->size());
 }
 
 binder::Status BinderIncrementalService::makeFile(
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index a49577b..6196c49 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -1166,11 +1166,11 @@
     if (!ifs) {
         return -EINVAL;
     }
-    if (data.size() > params.size) {
+    if ((IncFsSize)data.size() > params.size) {
         LOG(ERROR) << "Bad data size - bigger than file size";
         return -EINVAL;
     }
-    if (!data.empty() && data.size() != params.size) {
+    if (!data.empty() && (IncFsSize)data.size() != params.size) {
         // Writing a page is an irreversible operation, and it can't be updated with additional
         // data later. Check that the last written page is complete, or we may break the file.
         if (!isPageAligned(data.size())) {
@@ -3188,7 +3188,7 @@
 }
 
 FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
-    return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()});
+    return IncFs_FileIdFromMetadata({(const char*)metadata.data(), (IncFsSize)metadata.size()});
 }
 
 } // namespace android::incremental
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3402262..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.
@@ -2201,7 +2200,7 @@
                 Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
             }
             t.traceEnd();
-          
+
             if (!isWatch) {
                 t.traceBegin("StartTwilightService");
                 mSystemServiceManager.startService(TwilightService.class);
@@ -2709,7 +2708,7 @@
         t.traceEnd();
 
         t.traceBegin("ArtManagerLocal");
-        LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
+        LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal(context));
         t.traceEnd();
 
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
@@ -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 d322290..3c68662 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -205,6 +205,7 @@
                     .setRequiresDeviceIdle(true)
                     .setRequiresCharging(true)
                     .setPeriodic(BG_PROCESS_PERIOD)
+                    .setPriority(JobInfo.PRIORITY_MIN)
                     .build());
         }
 
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/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
index 4ef6875..54c3861 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
@@ -628,7 +628,7 @@
             CodePath.SAME, CodePath.DIFFERENT ->
                 throw AssertionError("secondDataPath cannot be a data path")
             CodePath.SYSTEM -> assertThat(codePaths[1]).isEqualTo(stubFile.parent.toString())
-            else -> {}
+            null -> {}
         }
     }
 
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..e4d124e89 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/jni/Android.bp b/services/tests/mockingservicestests/jni/Android.bp
index f454ac7..f1dc1fa 100644
--- a/services/tests/mockingservicestests/jni/Android.bp
+++ b/services/tests/mockingservicestests/jni/Android.bp
@@ -10,6 +10,8 @@
 cc_library_shared {
     name: "libmockingservicestestjni",
 
+    defaults: ["android.hardware.graphics.common-ndk_shared"],
+
     cflags: [
         "-Wall",
         "-Werror",
@@ -48,7 +50,6 @@
         "[email protected]",
         "[email protected]",
         "[email protected]",
-        "android.hardware.graphics.common-V3-ndk",
         "[email protected]",
         "[email protected]",
     ],
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/ExtendedMockitoTestCase.java b/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java
new file mode 100644
index 0000000..9aa28ce
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import android.util.Log;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+
+import org.junit.After;
+import org.junit.Before;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/**
+ * Base class to make it easier to write tests that uses {@code ExtendedMockito}.
+ *
+ */
+public abstract class ExtendedMockitoTestCase {
+
+    private static final String TAG = ExtendedMockitoTestCase.class.getSimpleName();
+
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private MockitoSession mSession;
+
+    @Before
+    public void startSession() {
+        if (DEBUG) {
+            Log.d(TAG, "startSession()");
+        }
+        StaticMockitoSessionBuilder builder = mockitoSession()
+                .initMocks(this)
+                .strictness(Strictness.LENIENT);
+        initializeSession(builder);
+        mSession = builder.startMocking();
+    }
+
+    /**
+     * Initializes the mockito session.
+     *
+     * <p>Typically used to define which classes should have static methods mocked or spied.
+     */
+    protected void initializeSession(StaticMockitoSessionBuilder builder) {
+        if (DEBUG) {
+            Log.d(TAG, "initializeSession()");
+        }
+    }
+
+    @After
+    public final void finishSession() {
+        if (mSession == null) {
+            Log.w(TAG, "finishSession(): no session");
+            return;
+        }
+        try {
+            if (DEBUG) {
+                Log.d(TAG, "finishSession()");
+            }
+        } finally {
+            // mSession.finishMocking() must ALWAYS be called (hence the over-protective try/finally
+            // statements), otherwise it would cause failures on future tests as mockito
+            // cannot start a session when a previous one is not finished
+            mSession.finishMocking();
+        }
+    }
+}
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/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
new file mode 100644
index 0000000..9bdc93e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -0,0 +1,490 @@
+/*
+ * 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.am;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.app.AppOpsManager;
+import android.app.BroadcastOptions;
+import android.app.IApplicationThread;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.LocalServices;
+import com.android.server.am.ActivityManagerService.Injector;
+import com.android.server.appop.AppOpsService;
+import com.android.server.wm.ActivityTaskManagerService;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Common tests for {@link BroadcastQueue} implementations.
+ */
+@MediumTest
+@RunWith(Parameterized.class)
+@SuppressWarnings("GuardedBy")
+public class BroadcastQueueTest {
+    private static final String TAG = "BroadcastQueueTest";
+
+    @Rule
+    public final ApplicationExitInfoTest.ServiceThreadRule
+            mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule();
+
+    private final Impl mImpl;
+
+    private enum Impl {
+        DEFAULT
+    }
+
+    private Context mContext;
+    private HandlerThread mHandlerThread;
+    private AtomicInteger mNextPid;
+
+    @Mock
+    private AppOpsService mAppOpsService;
+    @Mock
+    private ProcessList mProcessList;
+    @Mock
+    private PackageManagerInternal mPackageManagerInt;
+
+    private ActivityManagerService mAms;
+    private BroadcastQueue mQueue;
+
+    /**
+     * Map from PID to registered registered runtime receivers.
+     */
+    private SparseArray<ReceiverList> mRegisteredReceivers = new SparseArray<>();
+
+    @Parameters(name = "impl={0}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] { {Impl.DEFAULT} });
+    }
+
+    public BroadcastQueueTest(Impl impl) {
+        mImpl = impl;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+        mNextPid = new AtomicInteger(100);
+
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+        doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+        doNothing().when(mPackageManagerInt).setPackageStoppedState(any(), anyBoolean(), anyInt());
+
+        final ActivityManagerService realAms = new ActivityManagerService(
+                new TestInjector(mContext), mServiceThreadRule.getThread());
+        realAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+        realAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
+        realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
+        realAms.mPackageManagerInt = mPackageManagerInt;
+        mAms = spy(realAms);
+        doAnswer((invocation) -> {
+            Log.v(TAG, "Intercepting startProcessLocked() for "
+                    + Arrays.toString(invocation.getArguments()));
+            final String processName = invocation.getArgument(0);
+            final ApplicationInfo ai = invocation.getArgument(1);
+            final ProcessRecord res = makeActiveProcessRecord(ai, processName);
+            mHandlerThread.getThreadHandler().post(() -> {
+                mQueue.onApplicationAttachedLocked(res);
+            });
+            return res;
+        }).when(mAms).startProcessLocked(any(), any(), anyBoolean(), anyInt(),
+                any(), anyInt(), anyBoolean(), anyBoolean());
+
+        final BroadcastConstants constants = new BroadcastConstants(
+                Settings.Global.BROADCAST_FG_CONSTANTS);
+        final BroadcastSkipPolicy emptySkipPolicy = new BroadcastSkipPolicy(mAms) {
+            public boolean shouldSkip(BroadcastRecord r, ResolveInfo info) {
+                return false;
+            }
+            public boolean shouldSkip(BroadcastRecord r, BroadcastFilter filter) {
+                return false;
+            }
+        };
+        final BroadcastHistory emptyHistory = new BroadcastHistory() {
+            public void addBroadcastToHistoryLocked(BroadcastRecord original) {
+            }
+        };
+
+        if (mImpl == Impl.DEFAULT) {
+            mQueue = new BroadcastQueueImpl(mAms, mHandlerThread.getThreadHandler(), TAG,
+                    constants, emptySkipPolicy, emptyHistory, false,
+                    ProcessList.SCHED_GROUP_DEFAULT);
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private class TestInjector extends Injector {
+        TestInjector(Context context) {
+            super(context);
+        }
+
+        @Override
+        public AppOpsService getAppOpsService(File file, Handler handler) {
+            return mAppOpsService;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return mHandlerThread.getThreadHandler();
+        }
+
+        @Override
+        public ProcessList getProcessList(ActivityManagerService service) {
+            return mProcessList;
+        }
+    }
+
+    private ProcessRecord makeActiveProcessRecord(String packageName) throws Exception {
+        final ApplicationInfo ai = makeApplicationInfo(packageName);
+        return makeActiveProcessRecord(ai, ai.processName);
+    }
+
+    private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, String processName)
+            throws Exception {
+        final ProcessRecord r = new ProcessRecord(mAms, ai, processName, ai.uid);
+        r.setPid(mNextPid.getAndIncrement());
+
+        final IApplicationThread thread = mock(IApplicationThread.class);
+        final IBinder threadBinder = new Binder();
+        doReturn(threadBinder).when(thread).asBinder();
+        r.makeActive(thread, mAms.mProcessStats);
+        doReturn(r).when(mAms).getProcessRecordLocked(eq(r.info.processName), eq(r.info.uid));
+
+        final IIntentReceiver receiver = mock(IIntentReceiver.class);
+        final IBinder receiverBinder = new Binder();
+        doReturn(receiverBinder).when(receiver).asBinder();
+        final ReceiverList receiverList = new ReceiverList(mAms, r, r.getPid(), r.info.uid,
+                UserHandle.getUserId(r.info.uid), receiver);
+        mRegisteredReceivers.put(r.getPid(), receiverList);
+
+        doAnswer((invocation) -> {
+            Log.v(TAG, "Intercepting scheduleReceiver() for "
+                    + Arrays.toString(invocation.getArguments()));
+            mHandlerThread.getThreadHandler().post(() -> {
+                mQueue.finishReceiverLocked(r, Activity.RESULT_OK,
+                        null, null, false, false);
+            });
+            return null;
+        }).when(thread).scheduleReceiver(any(), any(), any(), anyInt(), any(), any(), anyBoolean(),
+                anyInt(), anyInt());
+
+        doAnswer((invocation) -> {
+            Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for "
+                    + Arrays.toString(invocation.getArguments()));
+            mHandlerThread.getThreadHandler().post(() -> {
+                mQueue.finishReceiverLocked(r, Activity.RESULT_OK, null, null,
+                        false, false);
+            });
+            return null;
+        }).when(thread).scheduleRegisteredReceiver(any(), any(), anyInt(), any(), any(),
+                anyBoolean(), anyBoolean(), anyInt(), anyInt());
+
+        return r;
+    }
+
+    private ApplicationInfo makeApplicationInfo(String packageName) {
+        final ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = packageName;
+        ai.processName = packageName;
+        ai.uid = getUidForPackage(packageName);
+        return ai;
+    }
+
+    private ResolveInfo makeManifestReceiver(String packageName, String name) {
+        final ResolveInfo ri = new ResolveInfo();
+        ri.activityInfo = new ActivityInfo();
+        ri.activityInfo.packageName = packageName;
+        ri.activityInfo.processName = packageName;
+        ri.activityInfo.name = name;
+        ri.activityInfo.applicationInfo = makeApplicationInfo(packageName);
+        return ri;
+    }
+
+    private BroadcastFilter makeRegisteredReceiver(ProcessRecord app) {
+        final ReceiverList receiverList = mRegisteredReceivers.get(app.getPid());
+        final IntentFilter filter = new IntentFilter();
+        final BroadcastFilter res = new BroadcastFilter(filter, receiverList,
+                receiverList.app.info.packageName, null, null, null, receiverList.uid,
+                receiverList.userId, false, false, true);
+        receiverList.add(res);
+        return res;
+    }
+
+    private BroadcastRecord makeBroadcastRecord(Intent intent, ProcessRecord callerApp,
+            List receivers) {
+        return makeBroadcastRecord(intent, callerApp, BroadcastOptions.makeBasic(), receivers);
+    }
+
+    private BroadcastRecord makeBroadcastRecord(Intent intent, ProcessRecord callerApp,
+            BroadcastOptions options, List receivers) {
+        return new BroadcastRecord(mQueue, intent, callerApp, callerApp.info.packageName, null,
+                callerApp.getPid(), callerApp.info.uid, false, null, null, null, null,
+                AppOpsManager.OP_NONE, options, receivers, null, Activity.RESULT_OK, null, null,
+                false, false, false, UserHandle.USER_SYSTEM, false, null, false, null);
+    }
+
+    private ArgumentMatcher<Intent> filterEqualsIgnoringComponent(Intent intent) {
+        final Intent intentClean = new Intent(intent);
+        intentClean.setComponent(null);
+        return (test) -> {
+            final Intent testClean = new Intent(test);
+            testClean.setComponent(null);
+            return intentClean.filterEquals(testClean);
+        };
+    }
+
+    private void waitForIdle() throws Exception {
+        mQueue.waitForIdle(null);
+    }
+
+    private void verifyScheduleReceiver(ProcessRecord app, Intent intent) throws Exception {
+        verify(app.getThread()).scheduleReceiver(
+                argThat(filterEqualsIgnoringComponent(intent)), any(), any(), anyInt(), any(),
+                any(), eq(false), eq(UserHandle.USER_SYSTEM), anyInt());
+    }
+
+    private void verifyScheduleRegisteredReceiver(ProcessRecord app, Intent intent)
+            throws Exception {
+        verify(app.getThread()).scheduleRegisteredReceiver(any(),
+                argThat(filterEqualsIgnoringComponent(intent)), anyInt(), any(), any(),
+                anyBoolean(), anyBoolean(), eq(UserHandle.USER_SYSTEM), anyInt());
+    }
+
+    private static final String PACKAGE_RED = "com.example.red";
+    private static final String PACKAGE_GREEN = "com.example.green";
+    private static final String PACKAGE_BLUE = "com.example.blue";
+    private static final String PACKAGE_YELLOW = "com.example.yellow";
+
+    private static final String CLASS_RED = "com.example.red.Red";
+    private static final String CLASS_GREEN = "com.example.green.Green";
+    private static final String CLASS_BLUE = "com.example.blue.Blue";
+    private static final String CLASS_YELLOW = "com.example.yellow.Yellow";
+
+    private static int getUidForPackage(String packageName) {
+        switch (packageName) {
+            case PACKAGE_RED: return android.os.Process.FIRST_APPLICATION_UID + 1;
+            case PACKAGE_GREEN: return android.os.Process.FIRST_APPLICATION_UID + 2;
+            case PACKAGE_BLUE: return android.os.Process.FIRST_APPLICATION_UID + 3;
+            case PACKAGE_YELLOW: return android.os.Process.FIRST_APPLICATION_UID + 4;
+            default: throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Verify dispatch of simple broadcast to single manifest receiver in
+     * already-running warm app.
+     */
+    @Test
+    public void testSimple_Manifest_Warm() throws Exception {
+        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+        final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
+
+        final Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(intent, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
+
+        waitForIdle();
+        verifyScheduleReceiver(receiverApp, intent);
+    }
+
+    /**
+     * Verify dispatch of multiple broadcasts to multiple manifest receivers in
+     * already-running warm apps.
+     */
+    @Test
+    public void testSimple_Manifest_Warm_Multiple() throws Exception {
+        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+
+        final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
+        final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
+
+        final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
+                        makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
+
+        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
+
+        waitForIdle();
+        verifyScheduleReceiver(receiverGreenApp, timezone);
+        verifyScheduleReceiver(receiverBlueApp, timezone);
+        verifyScheduleReceiver(receiverBlueApp, airplane);
+    }
+
+    /**
+     * Verify dispatch of multiple broadcast to multiple manifest receivers in
+     * apps that require cold starts.
+     */
+    @Test
+    public void testSimple_Manifest_ColdThenWarm() throws Exception {
+        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+
+        // We purposefully dispatch into green twice; the first time cold and
+        // the second time it should already be running
+
+        final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
+                        makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE))));
+
+        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN))));
+
+        waitForIdle();
+        final ProcessRecord receiverGreenApp = mAms.getProcessRecordLocked(PACKAGE_GREEN,
+                getUidForPackage(PACKAGE_GREEN));
+        final ProcessRecord receiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
+                getUidForPackage(PACKAGE_BLUE));
+        assertTrue(receiverBlueApp.getPid() > receiverGreenApp.getPid());
+        verifyScheduleReceiver(receiverGreenApp, timezone);
+        verifyScheduleReceiver(receiverGreenApp, airplane);
+        verifyScheduleReceiver(receiverBlueApp, timezone);
+    }
+
+    /**
+     * Verify dispatch of simple broadcast to single registered receiver in
+     * already-running warm app.
+     */
+    @Test
+    public void testSimple_Registered() throws Exception {
+        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+        final ProcessRecord receiverApp = makeActiveProcessRecord(PACKAGE_GREEN);
+
+        final Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(intent, callerApp,
+                List.of(makeRegisteredReceiver(receiverApp))));
+
+        waitForIdle();
+        verifyScheduleRegisteredReceiver(receiverApp, intent);
+    }
+
+    /**
+     * Verify dispatch of multiple broadcasts to multiple registered receivers
+     * in already-running warm apps.
+     */
+    @Test
+    public void testSimple_Registered_Multiple() throws Exception {
+        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+
+        final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
+        final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
+
+        final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
+                List.of(makeRegisteredReceiver(receiverGreenApp),
+                        makeRegisteredReceiver(receiverBlueApp))));
+
+        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
+                List.of(makeRegisteredReceiver(receiverBlueApp))));
+
+        waitForIdle();
+        verifyScheduleRegisteredReceiver(receiverGreenApp, timezone);
+        verifyScheduleRegisteredReceiver(receiverBlueApp, timezone);
+        verifyScheduleRegisteredReceiver(receiverBlueApp, airplane);
+    }
+
+    /**
+     * Verify dispatch of multiple broadcasts mixed to both manifest and
+     * registered receivers, to both warm and cold apps.
+     */
+    @Test
+    public void testComplex() throws Exception {
+        final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
+
+        final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN);
+        final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
+
+        final Intent timezone = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(timezone, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_GREEN, CLASS_GREEN),
+                        makeRegisteredReceiver(receiverGreenApp),
+                        makeManifestReceiver(PACKAGE_BLUE, CLASS_BLUE),
+                        makeRegisteredReceiver(receiverYellowApp))));
+
+        final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        mQueue.enqueueBroadcastLocked(makeBroadcastRecord(airplane, callerApp,
+                List.of(makeManifestReceiver(PACKAGE_YELLOW, CLASS_YELLOW))));
+
+        waitForIdle();
+        final ProcessRecord receiverBlueApp = mAms.getProcessRecordLocked(PACKAGE_BLUE,
+                getUidForPackage(PACKAGE_BLUE));
+        verifyScheduleReceiver(receiverGreenApp, timezone);
+        verifyScheduleRegisteredReceiver(receiverGreenApp, timezone);
+        verifyScheduleReceiver(receiverBlueApp, timezone);
+        verifyScheduleRegisteredReceiver(receiverYellowApp, timezone);
+        verifyScheduleReceiver(receiverYellowApp, airplane);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 598c6b0..1c34548 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -317,11 +317,11 @@
         ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
         doReturn(true).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
-                any(ArraySet.class));
+                any(int[].class));
         sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
         sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
         doReturn(false).when(sService).isReceivingBroadcastLocked(any(ProcessRecord.class),
-                any(ArraySet.class));
+                any(int[].class));
 
         assertProcStates(app, PROCESS_STATE_RECEIVER, FOREGROUND_APP_ADJ, SCHED_GROUP_BACKGROUND);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
index 03eff2a..e170e98 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceControllerTest.java
@@ -258,7 +258,7 @@
                                 PROVIDER_A_SERVICE_A,
                                 PROVIDER_A_SERVICE_C));
         FakeGameServiceProviderInstance instanceB =
-                seedConfigurationForUser(USER_10, configurationA);
+                seedConfigurationForUser(USER_10, configurationB);
         Intent intent = new Intent();
         intent.setData(Uri.parse("package:" + PROVIDER_A_PACKAGE_NAME));
         broadcastReceiverArgumentCaptor.getValue().onReceive(mMockContext, intent);
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index e4f9eaf..3f16a98 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -28,7 +28,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -36,7 +35,6 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 
-import android.Manifest;
 import android.annotation.Nullable;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerInternal;
@@ -98,7 +96,6 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.Objects;
 import java.util.function.Consumer;
 
 
@@ -361,7 +358,6 @@
             throws Exception {
         mGameServiceProviderInstance.start();
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty();
@@ -383,7 +379,6 @@
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSessionService.CapturedCreateInvocation capturedCreateInvocation =
@@ -398,7 +393,6 @@
         mGameServiceProviderInstance.start();
         dispatchTaskCreated(10, GAME_A_MAIN_ACTIVITY);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty();
@@ -408,7 +402,6 @@
     public void gameTaskStartedAndSessionRequested_createsGameSession() throws Exception {
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -426,9 +419,7 @@
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         CreateGameSessionRequest expectedCreateGameSessionRequest = new CreateGameSessionRequest(10,
@@ -442,7 +433,6 @@
     public void gameSessionSuccessfullyCreated_createsTaskOverlay() throws Exception {
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -462,7 +452,6 @@
         startTask(10, GAME_A_MAIN_ACTIVITY);
         startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -488,7 +477,6 @@
         startTask(11, GAME_A_MAIN_ACTIVITY);
         startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
         mFakeGameService.requestCreateGameSession(11);
 
@@ -522,7 +510,6 @@
         startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
         startProcessForPackage(secondGameProcessId, GAME_A_PACKAGE);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -551,7 +538,6 @@
         startTask(10, GAME_A_MAIN_ACTIVITY);
         startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -583,7 +569,6 @@
         startTask(11, GAME_A_MAIN_ACTIVITY);
         startProcessForPackage(firstGameProcessId, GAME_A_PACKAGE);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
 
         mFakeGameService.requestCreateGameSession(10);
         mFakeGameService.requestCreateGameSession(11);
@@ -624,7 +609,6 @@
         startTask(10, GAME_A_MAIN_ACTIVITY);
         startProcessForPackage(gameProcessId, GAME_A_PACKAGE);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
 
         // No game session should be created.
         assertThat(mFakeGameSessionService.getCapturedCreateInvocations()).isEmpty();
@@ -636,7 +620,6 @@
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -677,7 +660,6 @@
     public void systemBarsTransientShownDueToGesture_hasGameSession_propagatesToGameSession() {
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -699,7 +681,6 @@
     public void systemBarsTransientShownButNotGesture_hasGameSession_notPropagatedToGameSession() {
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -721,7 +702,6 @@
     public void gameTaskFocused_propagatedToGameSession() throws Exception {
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -747,7 +727,6 @@
 
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -764,7 +743,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         dispatchTaskRemoved(10);
@@ -782,7 +760,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -800,7 +777,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -830,7 +806,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -851,7 +826,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -879,7 +853,6 @@
         startTask(10, GAME_A_MAIN_ACTIVITY);
         startTask(11, GAME_A_MAIN_ACTIVITY);
 
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -897,7 +870,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -925,7 +897,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -955,7 +926,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -989,19 +959,10 @@
     }
 
     @Test
-    public void createGameSession_failurePermissionDenied() throws Exception {
-        mGameServiceProviderInstance.start();
-        startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionDenied(Manifest.permission.MANAGE_GAME_ACTIVITY);
-        assertThrows(SecurityException.class, () -> mFakeGameService.requestCreateGameSession(10));
-    }
-
-    @Test
     public void gameSessionServiceDies_severalActiveGameSessions_destroysGameSessions() {
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -1030,7 +991,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -1058,7 +1018,6 @@
     public void takeScreenshot_failureNoBitmapCaptured() throws Exception {
         mGameServiceProviderInstance.start();
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -1093,7 +1052,6 @@
                 any(), any(), any(), anyInt(), anyInt(), any(), anyInt(), any(), any());
         mGameServiceProviderInstance.start();
         startTask(taskId, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(taskId);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -1113,7 +1071,6 @@
 
     @Test
     public void restartGame_taskIdAssociatedWithGame_restartsTargetGame() throws Exception {
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         Intent launchIntent = new Intent("com.test.ACTION_LAUNCH_GAME_PACKAGE")
                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         when(mMockPackageManager.getLaunchIntentForPackage(GAME_A_PACKAGE))
@@ -1122,7 +1079,6 @@
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -1148,11 +1104,9 @@
 
     @Test
     public void restartGame_taskIdNotAssociatedWithGame_noOp() throws Exception {
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mGameServiceProviderInstance.start();
 
         startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
         mFakeGameService.requestCreateGameSession(10);
 
         FakeGameSession gameSession10 = new FakeGameSession();
@@ -1170,21 +1124,6 @@
                 .restartTaskActivityProcessIfVisible(anyInt(), anyString());
     }
 
-    @Test
-    public void restartGame_failurePermissionDenied() throws Exception {
-        mGameServiceProviderInstance.start();
-        startTask(10, GAME_A_MAIN_ACTIVITY);
-        mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
-        mFakeGameService.requestCreateGameSession(10);
-        IGameSessionController gameSessionController = Objects.requireNonNull(getOnlyElement(
-                mFakeGameSessionService.getCapturedCreateInvocations())).mGameSessionController;
-        mockPermissionDenied(Manifest.permission.MANAGE_GAME_ACTIVITY);
-        assertThrows(SecurityException.class,
-                () -> gameSessionController.restartGame(10));
-        verify(mActivityTaskManagerInternal, never())
-                .restartTaskActivityProcessIfVisible(anyInt(), anyString());
-    }
-
     private void startTask(int taskId, ComponentName componentName) {
         addRunningTaskInfo(taskId, componentName);
 
@@ -1261,14 +1200,6 @@
         }
     }
 
-    private void mockPermissionGranted(String permission) {
-        mMockContext.setPermission(permission, PackageManager.PERMISSION_GRANTED);
-    }
-
-    private void mockPermissionDenied(String permission) {
-        mMockContext.setPermission(permission, PackageManager.PERMISSION_DENIED);
-    }
-
     private void dispatchTaskSystemBarsEvent(
             ThrowingConsumer<TaskSystemBarsListener> taskSystemBarsListenerConsumer) {
         for (TaskSystemBarsListener listener : mTaskSystemBarsListeners) {
@@ -1409,42 +1340,12 @@
     }
 
     private final class MockContext extends ContextWrapper {
-        // Map of permission name -> PermissionManager.Permission_{GRANTED|DENIED} constant
-        private final HashMap<String, Integer> mMockedPermissions = new HashMap<>();
-
         MockContext(Context base) {
             super(base);
         }
-
-        /**
-         * Mock checks for the specified permission, and have them behave as per {@code granted}.
-         *
-         * <p>Passing null reverts to default behavior, which does a real permission check on the
-         * test package.
-         *
-         * @param granted One of {@link PackageManager#PERMISSION_GRANTED} or
-         *                {@link PackageManager#PERMISSION_DENIED}.
-         */
-        public void setPermission(String permission, Integer granted) {
-            mMockedPermissions.put(permission, granted);
-        }
-
         @Override
         public PackageManager getPackageManager() {
             return mMockPackageManager;
         }
-
-        @Override
-        public void enforceCallingPermission(String permission, @Nullable String message) {
-            final Integer granted = mMockedPermissions.get(permission);
-            if (granted == null) {
-                super.enforceCallingOrSelfPermission(permission, message);
-                return;
-            }
-
-            if (!granted.equals(PackageManager.PERMISSION_GRANTED)) {
-                throw new SecurityException("[Test] permission denied: " + permission);
-            }
-        }
     }
 }
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..9acc5b9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -58,7 +58,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;
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 60ddeeb..3866da3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -152,9 +152,9 @@
         when(mMockedResources.obtainTypedArray(
                 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
                 .thenReturn(mockArray);
-        when(mMockedResources.obtainTypedArray(
+        when(mMockedResources.getIntArray(
                 com.android.internal.R.array.config_autoBrightnessLevels))
-                .thenReturn(mockArray);
+                .thenReturn(new int[]{});
     }
 
     @After
@@ -798,11 +798,13 @@
     @Test
     public void testGetSystemPreferredDisplayMode() throws Exception {
         SurfaceControl.DisplayMode displayMode1 = createFakeDisplayMode(0, 1920, 1080, 60f);
-        // preferred mode
+        // system preferred mode
         SurfaceControl.DisplayMode displayMode2 = createFakeDisplayMode(1, 3840, 2160, 60f);
+        // user preferred mode
+        SurfaceControl.DisplayMode displayMode3 = createFakeDisplayMode(2, 1920, 1080, 30f);
 
         SurfaceControl.DisplayMode[] modes =
-                new SurfaceControl.DisplayMode[]{displayMode1, displayMode2};
+                new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, displayMode3};
         FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, 1);
         setUpDisplay(display);
         updateAvailableDisplays();
@@ -814,24 +816,43 @@
 
         DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(
                 0).getDisplayDeviceInfoLocked();
-
         assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
-
         Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
+        assertThat(matches(defaultMode, displayMode1)).isTrue();
+
+        // Set the user preferred display mode
+        mListener.addedDisplays.get(0).setUserPreferredDisplayModeLocked(
+                new Display.Mode(
+                        displayMode3.width, displayMode3.height, displayMode3.refreshRate));
+        updateAvailableDisplays();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        displayDeviceInfo = mListener.addedDisplays.get(
+                0).getDisplayDeviceInfoLocked();
+        defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
+        assertThat(matches(defaultMode, displayMode3)).isTrue();
+
+        // clear the user preferred mode
+        mListener.addedDisplays.get(0).setUserPreferredDisplayModeLocked(null);
+        updateAvailableDisplays();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+        displayDeviceInfo = mListener.addedDisplays.get(
+                0).getDisplayDeviceInfoLocked();
+        defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
         assertThat(matches(defaultMode, displayMode2)).isTrue();
 
-        // Change the display and add new preferred mode
-        SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(2, 2340, 1080, 60f);
-        modes = new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, addedDisplayInfo};
+        // Change the display and add new system preferred mode
+        SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3, 2340, 1080, 20f);
+        modes = new SurfaceControl.DisplayMode[]{
+                displayMode1, displayMode2, displayMode3, addedDisplayInfo};
         display.dynamicInfo.supportedDisplayModes = modes;
-        display.dynamicInfo.preferredBootDisplayMode = 2;
+        display.dynamicInfo.preferredBootDisplayMode = 3;
         setUpDisplay(display);
         mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
         waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
 
         assertTrue(mListener.traversalRequested);
         assertThat(mListener.addedDisplays.size()).isEqualTo(1);
-        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
+        assertThat(mListener.changedDisplays.size()).isEqualTo(3);
 
         DisplayDevice displayDevice = mListener.changedDisplays.get(0);
         displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
index 0eb0a00..1d08a80d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/FlexibilityControllerTest.java
@@ -561,14 +561,14 @@
             assertEquals(0, trackedJobs.get(4).size());
 
             flexTracker.resetJobNumDroppedConstraints(jobs[0], FROZEN_TIME);
-            assertEquals(2, trackedJobs.get(0).size());
+            assertEquals(1, trackedJobs.get(0).size());
             assertEquals(0, trackedJobs.get(1).size());
             assertEquals(0, trackedJobs.get(2).size());
             assertEquals(2, trackedJobs.get(3).size());
             assertEquals(0, trackedJobs.get(4).size());
 
             flexTracker.adjustJobsRequiredConstraints(jobs[0], -2, FROZEN_TIME);
-            assertEquals(2, trackedJobs.get(0).size());
+            assertEquals(1, trackedJobs.get(0).size());
             assertEquals(1, trackedJobs.get(1).size());
             assertEquals(0, trackedJobs.get(2).size());
             assertEquals(1, trackedJobs.get(3).size());
@@ -580,7 +580,7 @@
                     Clock.fixed(Instant.ofEpochMilli(nowElapsed), ZoneOffset.UTC);
 
             flexTracker.resetJobNumDroppedConstraints(jobs[0], nowElapsed);
-            assertEquals(2, trackedJobs.get(0).size());
+            assertEquals(1, trackedJobs.get(0).size());
             assertEquals(0, trackedJobs.get(1).size());
             assertEquals(1, trackedJobs.get(2).size());
             assertEquals(1, trackedJobs.get(3).size());
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..574bab2
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerInternalTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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_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..538adb2
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
@@ -0,0 +1,684 @@
+/*
+ * 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();
+        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+
+        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() {
+        setUserState(PROFILE_USER_ID, UserState.STATE_RUNNING_UNLOCKED);
+    }
+
+    protected final void stopDefaultProfile() {
+        setUserState(PROFILE_USER_ID, 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
new file mode 100644
index 0000000..8388a70
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -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.server.pm;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.app.ActivityManagerInternal;
+import android.os.UserHandle;
+
+import org.junit.Test;
+
+/**
+ * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest}
+ */
+public final class UserManagerServiceTest extends UserManagerServiceOrInternalTestCase {
+
+    @Test
+    public void testGetCurrentUserId_amInternalNotReady() {
+        mockGetLocalService(ActivityManagerInternal.class, null);
+
+        assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
+                .isEqualTo(UserHandle.USER_NULL);
+    }
+
+    @Test
+    public void testGetCurrentUserId() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("getCurrentUserId()").that(mUms.getCurrentUserId())
+                .isEqualTo(USER_ID);
+    }
+
+    @Test
+    public void testIsCurrentUserOrRunningProfileOfCurrentUser_currentUser() {
+        mockCurrentUser(USER_ID);
+
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsCurrentUserOrRunningProfileOfCurrentUser_notCurrentUser() {
+        mockCurrentUser(OTHER_USER_ID);
+
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(USER_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsCurrentUserOrRunningProfileOfCurrentUser_startedProfileOfCurrentUser() {
+        addDefaultProfileAndParent();
+        startDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
+
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isTrue();
+    }
+
+    @Test
+    public void testIsCurrentUserOrRunningProfileOfCurrentUser_stoppedProfileOfCurrentUser() {
+        addDefaultProfileAndParent();
+        stopDefaultProfile();
+        mockCurrentUser(PARENT_USER_ID);
+
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
+    }
+
+    @Test
+    public void testIsCurrentUserOrRunningProfileOfCurrentUser_profileOfNonCurrentUSer() {
+        addDefaultProfileAndParent();
+        mockCurrentUser(OTHER_USER_ID);
+
+        assertWithMessage("isCurrentUserOrRunningProfileOfCurrentUser(%s)", PROFILE_USER_ID)
+                .that(mUms.isCurrentUserOrRunningProfileOfCurrentUser(PROFILE_USER_ID)).isFalse();
+    }
+
+    @Override
+    protected boolean isUserVisible(int userId) {
+        return mUms.isUserVisibleUnchecked(userId);
+    }
+
+    @Override
+    protected boolean isUserVisibleOnDisplay(int userId, int displayId) {
+        return mUms.isUserVisibleOnDisplay(userId, displayId);
+    }
+
+    @Override
+    protected int getDisplayAssignedToUser(int userId) {
+        return mUms.getDisplayAssignedToUser(userId);
+    }
+
+    @Override
+    protected int getUserAssignedToDisplay(int displayId) {
+        return mUms.getUserAssignedToDisplay(displayId);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 9d26971..fb9cbb0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -61,7 +61,6 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -1029,44 +1028,4 @@
             return mPackageInfo.applicationInfo.splitSourceDirs[length - 1];
         }
     }
-
-    private boolean shouldPackageRunOob(boolean isDefaultEnabled, String whitelist,
-            Collection<String> packageNamesInSameProcess) {
-        return DexManager.isPackageSelectedToRunOobInternal(
-                isDefaultEnabled, whitelist, packageNamesInSameProcess);
-    }
-
-    @Test
-    public void testOobPackageSelectionDefault() {
-        // Feature is off by default, not overriden
-        assertFalse(shouldPackageRunOob(false, "ALL", null));
-    }
-
-    @Test
-    public void testOobPackageSelectionWhitelist() {
-        // Various allowlist of apps to run in OOB mode.
-        final String kWhitelistApp0 = "com.priv.app0";
-        final String kWhitelistApp1 = "com.priv.app1";
-        final String kWhitelistApp2 = "com.priv.app2";
-        final String kWhitelistApp1AndApp2 = "com.priv.app1,com.priv.app2";
-
-        // Packages that shares the targeting process.
-        final Collection<String> runningPackages = Arrays.asList("com.priv.app1", "com.priv.app2");
-
-        // Feature is off, allowlist does not matter
-        assertFalse(shouldPackageRunOob(false, kWhitelistApp0, runningPackages));
-        assertFalse(shouldPackageRunOob(false, kWhitelistApp1, runningPackages));
-        assertFalse(shouldPackageRunOob(false, "", runningPackages));
-        assertFalse(shouldPackageRunOob(false, "ALL", runningPackages));
-
-        // Feature is on, app not in allowlist
-        assertFalse(shouldPackageRunOob(true, kWhitelistApp0, runningPackages));
-        assertFalse(shouldPackageRunOob(true, "", runningPackages));
-
-        // Feature is on, app in allowlist
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp1, runningPackages));
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp2, runningPackages));
-        assertTrue(shouldPackageRunOob(true, kWhitelistApp1AndApp2, runningPackages));
-        assertTrue(shouldPackageRunOob(true, "ALL", runningPackages));
-    }
 }
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/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/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 0483a60..7ae70eb 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -147,6 +147,19 @@
                 android:resource="@xml/test_dream_metadata" />
         </service>
 
+        <service
+            android:name="com.android.server.dreams.TestDreamServiceWithInvalidSettings"
+            android:exported="false"
+            android:label="Test Dream" >
+            <intent-filter>
+                <action android:name="android.service.dreams.DreamService" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <meta-data
+                android:name="android.service.dream"
+                android:resource="@xml/test_dream_metadata_invalid" />
+        </service>
+
         <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
              android:permission="android.permission.BIND_DEVICE_ADMIN"
              android:exported="true">
diff --git a/services/tests/servicestests/res/xml/test_dream_metadata.xml b/services/tests/servicestests/res/xml/test_dream_metadata.xml
index aa054f1..9905c69 100644
--- a/services/tests/servicestests/res/xml/test_dream_metadata.xml
+++ b/services/tests/servicestests/res/xml/test_dream_metadata.xml
@@ -15,5 +15,5 @@
   -->
 
 <dream xmlns:android="http://schemas.android.com/apk/res/android"
-       android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
+       android:settingsActivity="com.android.frameworks.servicestests/.TestDreamSettingsActivity"
        android:showClockAndComplications="false" />
diff --git a/services/tests/servicestests/res/xml/test_dream_metadata_invalid.xml b/services/tests/servicestests/res/xml/test_dream_metadata_invalid.xml
new file mode 100644
index 0000000..47864d9
--- /dev/null
+++ b/services/tests/servicestests/res/xml/test_dream_metadata_invalid.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ 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.
+  -->
+
+<!-- The settings activity is in a different package, which is invalid -->
+<dream xmlns:android="http://schemas.android.com/apk/res/android"
+       android:settingsActivity="com.android.server.dreams/.TestDreamSettingsActivity"
+       android:showClockAndComplications="false"/>
diff --git a/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java b/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java
index f92f5ea..3a592cd 100644
--- a/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/SystemServiceManagerTest.java
@@ -81,4 +81,10 @@
         assertEquals(1, counter.get());
     }
 
+    @Test
+    public void onUserCompletedEventShouldNotThrowExceptionWithStoppedOrUnknownUser() {
+        mSystemServiceManager.onUserCompletedEvent(99,
+                SystemService.UserCompletedEventType.EVENT_TYPE_USER_STARTING);
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
index 464fee2..e165f06 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterTest.java
@@ -24,6 +24,7 @@
 import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
 import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_FILTER_KEY_EVENTS;
 import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
+import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_SOFTWARE_CURSOR;
 import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
 import static com.android.server.accessibility.AccessibilityInputFilter.FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER;
 
@@ -52,6 +53,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
+import com.android.server.accessibility.cursor.SoftwareCursorGestureHandler;
 import com.android.server.accessibility.gestures.TouchExplorer;
 import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
 import com.android.server.accessibility.magnification.MagnificationGestureHandler;
@@ -83,6 +85,7 @@
     private final ArrayList<Display> mDisplayList = new ArrayList<>();
     private final int mFeatures = FLAG_FEATURE_AUTOCLICK
             | FLAG_FEATURE_TOUCH_EXPLORATION
+            | FLAG_FEATURE_SOFTWARE_CURSOR
             | FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER
             | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
             | FLAG_FEATURE_INJECT_MOTION_EVENTS
@@ -91,8 +94,8 @@
     // The expected order of EventStreamTransformations.
     private final Class[] mExpectedEventHandlerTypes =
             {KeyboardInterceptor.class, MotionEventInjector.class,
-                    FullScreenMagnificationGestureHandler.class, TouchExplorer.class,
-                    AutoclickController.class, AccessibilityInputFilter.class};
+                    SoftwareCursorGestureHandler.class, FullScreenMagnificationGestureHandler.class,
+                    TouchExplorer.class, AutoclickController.class, AccessibilityInputFilter.class};
 
     @Mock private WindowManagerInternal.AccessibilityControllerInternal mMockA11yController;
     @Mock private WindowManagerInternal mMockWindowManagerService;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
index ed0336a..9475d0f 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityUserStateTest.java
@@ -149,6 +149,7 @@
         mUserState.setTargetAssignedToAccessibilityButton(COMPONENT_NAME.flattenToString());
         mUserState.setTouchExplorationEnabledLocked(true);
         mUserState.setDisplayMagnificationEnabledLocked(true);
+        mUserState.setSoftwareCursorEnabledLocked(true);
         mUserState.setAutoclickEnabledLocked(true);
         mUserState.setUserNonInteractiveUiTimeoutLocked(30);
         mUserState.setUserInteractiveUiTimeoutLocked(30);
@@ -171,6 +172,7 @@
         assertNull(mUserState.getTargetAssignedToAccessibilityButton());
         assertFalse(mUserState.isTouchExplorationEnabledLocked());
         assertFalse(mUserState.isDisplayMagnificationEnabledLocked());
+        assertFalse(mUserState.isSoftwareCursorEnabledLocked());
         assertFalse(mUserState.isAutoclickEnabledLocked());
         assertEquals(0, mUserState.getUserNonInteractiveUiTimeoutLocked());
         assertEquals(0, mUserState.getUserInteractiveUiTimeoutLocked());
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/accessibility/MotionEventInjectorTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
index 59b69f9..233caf9 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MotionEventInjectorTest.java
@@ -837,7 +837,7 @@
 
             @Override
             public void describeTo(Description description) {
-                description.appendText("Contains points " + points);
+                description.appendText("Contains points " + Arrays.toString(points));
             }
         };
     }
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..fe079f4 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,11 @@
             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);
             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 +201,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());
@@ -611,6 +639,7 @@
         setUpAndStartUserInBackground(TEST_USER_ID1);
         assertThrows(IllegalArgumentException.class,
                 () -> mUserController.stopProfile(TEST_USER_ID1));
+        verifyUserUnassignedFromDisplayNeverCalled(TEST_USER_ID);
     }
 
     @Test
@@ -623,13 +652,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 +722,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 +918,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/ambientcontext/AmbientContextManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java
index 6bb494d3..c75abf8 100644
--- a/services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ambientcontext/AmbientContextManagerServiceTest.java
@@ -21,8 +21,8 @@
 import android.app.PendingIntent;
 import android.app.ambientcontext.AmbientContextEvent;
 import android.app.ambientcontext.AmbientContextEventRequest;
+import android.app.ambientcontext.IAmbientContextObserver;
 import android.content.Intent;
-import android.os.RemoteCallback;
 import android.os.UserHandle;
 
 import androidx.test.InstrumentationRegistry;
@@ -30,6 +30,8 @@
 
 import org.junit.Test;
 
+import java.util.List;
+
 /**
  * Unit test for {@link AmbientContextManagerService}.
  * atest FrameworksServicesTests:AmbientContextManagerServiceTest
@@ -48,12 +50,22 @@
         PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 InstrumentationRegistry.getTargetContext(), 0,
                 intent, PendingIntent.FLAG_IMMUTABLE);
+        IAmbientContextObserver observer = new IAmbientContextObserver.Stub() {
+            @Override
+            public void onEvents(List<AmbientContextEvent> events) {
+            }
+
+            @Override
+            public void onRegistrationComplete(int statusCode) {
+            }
+        };
         AmbientContextManagerService.ClientRequest clientRequest =
                 new AmbientContextManagerService.ClientRequest(USER_ID, request,
-                        pendingIntent, new RemoteCallback(result -> {}));
+                        pendingIntent.getCreatorPackage(), observer);
 
         assertThat(clientRequest.getRequest()).isEqualTo(request);
         assertThat(clientRequest.getPackageName()).isEqualTo(SYSTEM_PACKAGE_NAME);
+        assertThat(clientRequest.getObserver()).isEqualTo(observer);
         assertThat(clientRequest.hasUserId(USER_ID)).isTrue();
         assertThat(clientRequest.hasUserId(-1)).isFalse();
         assertThat(clientRequest.hasUserIdAndPackageName(USER_ID, SYSTEM_PACKAGE_NAME)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
index b17c3a1..428eaff 100644
--- a/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/SpatializerHelperTest.java
@@ -55,14 +55,20 @@
         mMockAudioService = mock(AudioService.class);
         mSpyAudioSystem = spy(new NoOpAudioSystemAdapter());
 
-        mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem);
+        mSpatHelper = new SpatializerHelper(mMockAudioService, mSpyAudioSystem,
+                false /*headTrackingEnabledByDefault*/);
     }
 
+    /**
+     * Test that constructing an SADeviceState instance requires a non-null address for a
+     * wireless type, but can take null for a non-wireless type;
+     * @throws Exception
+     */
     @Test
     public void testSADeviceStateNullAddressCtor() throws Exception {
         try {
-            SADeviceState devState = new SADeviceState(
-                    AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null);
+            SADeviceState devState = new SADeviceState(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, null);
+            devState = new SADeviceState(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP, null);
             Assert.fail();
         } catch (NullPointerException e) { }
     }
@@ -88,11 +94,12 @@
         final AudioDeviceAttributes dev1 =
                 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
         final AudioDeviceAttributes dev2 =
-                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "C3:P0:beep");
+                new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "C3:PO:beep");
         final AudioDeviceAttributes dev3 =
                 new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "R2:D2:bloop");
 
         doNothing().when(mMockAudioService).persistSpatialAudioDeviceSettings();
+        mSpatHelper.initForTest(true /*binaural*/, true /*transaural*/);
 
         // test with single device
         mSpatHelper.addCompatibleAudioDevice(dev1);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
new file mode 100644
index 0000000..10f0a5c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/ALSProbeTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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.biometrics.log;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.hardware.input.InputSensorInfo;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class ALSProbeTest {
+
+    private static final long TIMEOUT_MS = 1000;
+
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private SensorManager mSensorManager;
+    @Captor
+    private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;
+
+    private TestableLooper mLooper;
+    private Sensor mLightSensor = new Sensor(
+            new InputSensorInfo("", "", 0, 0, Sensor.TYPE_LIGHT, 0, 0, 0, 0, 0, 0,
+                    "", "", 0, 0, 0));
+
+    private ALSProbe mProbe;
+
+    @Before
+    public void setup() {
+        mLooper = TestableLooper.get(this);
+        when(mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mLightSensor);
+        mProbe = new ALSProbe(mSensorManager, new Handler(mLooper.getLooper()), TIMEOUT_MS - 1);
+        reset(mSensorManager);
+    }
+
+    @Test
+    public void testEnable() {
+        final float value = 2.0f;
+        mProbe.enable();
+        verify(mSensorManager).registerListener(
+                mSensorEventListenerCaptor.capture(), any(), anyInt());
+
+        mSensorEventListenerCaptor.getValue().onSensorChanged(
+                new SensorEvent(mLightSensor, 1, 1, new float[]{4.0f}));
+        mSensorEventListenerCaptor.getValue().onSensorChanged(
+                new SensorEvent(mLightSensor, 1, 2, new float[]{value}));
+
+        assertThat(mProbe.getCurrentLux()).isEqualTo(value);
+    }
+
+    @Test
+    public void testEnableOnlyOnce() {
+        mProbe.enable();
+        mProbe.enable();
+
+        verify(mSensorManager).registerListener(any(), any(), anyInt());
+        verifyNoMoreInteractions(mSensorManager);
+    }
+
+    @Test
+    public void testDisable() {
+        mProbe.enable();
+        verify(mSensorManager).registerListener(
+                mSensorEventListenerCaptor.capture(), any(), anyInt());
+        mProbe.disable();
+
+        verify(mSensorManager).unregisterListener(eq(mSensorEventListenerCaptor.getValue()));
+        verifyNoMoreInteractions(mSensorManager);
+    }
+
+    @Test
+    public void testDestroy() {
+        mProbe.destroy();
+        mProbe.enable();
+
+        verify(mSensorManager, never()).registerListener(any(), any(), anyInt());
+        verifyNoMoreInteractions(mSensorManager);
+    }
+
+    @Test
+    public void testDisabledReportsNegativeValue() {
+        assertThat(mProbe.getCurrentLux()).isLessThan(0f);
+
+        mProbe.enable();
+        verify(mSensorManager).registerListener(
+                mSensorEventListenerCaptor.capture(), any(), anyInt());
+        mSensorEventListenerCaptor.getValue().onSensorChanged(
+                new SensorEvent(mLightSensor, 1, 1, new float[]{4.0f}));
+        mProbe.disable();
+
+        assertThat(mProbe.getCurrentLux()).isLessThan(0f);
+    }
+
+    @Test
+    public void testWatchDog() {
+        mProbe.enable();
+        verify(mSensorManager).registerListener(
+                mSensorEventListenerCaptor.capture(), any(), anyInt());
+        mSensorEventListenerCaptor.getValue().onSensorChanged(
+                new SensorEvent(mLightSensor, 1, 1, new float[]{4.0f}));
+        moveTimeBy(TIMEOUT_MS);
+
+        verify(mSensorManager).unregisterListener(eq(mSensorEventListenerCaptor.getValue()));
+        verifyNoMoreInteractions(mSensorManager);
+        assertThat(mProbe.getCurrentLux()).isLessThan(0f);
+    }
+
+    @Test
+    public void testEnableExtendsWatchDog() {
+        mProbe.enable();
+        verify(mSensorManager).registerListener(any(), any(), anyInt());
+
+        moveTimeBy(TIMEOUT_MS / 2);
+        verify(mSensorManager, never()).unregisterListener(any(SensorEventListener.class));
+
+        mProbe.enable();
+        moveTimeBy(TIMEOUT_MS);
+
+        verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
+        verifyNoMoreInteractions(mSensorManager);
+        assertThat(mProbe.getCurrentLux()).isLessThan(0f);
+    }
+
+    private void moveTimeBy(long millis) {
+        mLooper.moveTimeForward(millis);
+        mLooper.processAllMessages();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
index e6acc90..dd7aeb7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricContextProviderTest.java
@@ -40,8 +40,6 @@
 import com.android.internal.statusbar.ISessionListener;
 import com.android.internal.statusbar.IStatusBarService;
 
-import com.google.common.collect.ImmutableList;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -89,33 +87,64 @@
 
     @Test
     public void testIsAod() throws RemoteException {
-        mListener.onDozeChanged(true);
+        mListener.onDozeChanged(true /* isDozing */, false /* isAwake */);
         assertThat(mProvider.isAod()).isTrue();
-        mListener.onDozeChanged(false);
+        mListener.onDozeChanged(false /* isDozing */, false /* isAwake */);
         assertThat(mProvider.isAod()).isFalse();
 
         when(mAmbientDisplayConfiguration.alwaysOnEnabled(anyInt())).thenReturn(false);
-        mListener.onDozeChanged(true);
+        mListener.onDozeChanged(true /* isDozing */, false /* isAwake */);
         assertThat(mProvider.isAod()).isFalse();
-        mListener.onDozeChanged(false);
+        mListener.onDozeChanged(false /* isDozing */, false /* isAwake */);
         assertThat(mProvider.isAod()).isFalse();
     }
 
     @Test
+    public void testIsAwake() throws RemoteException {
+        mListener.onDozeChanged(false /* isDozing */, true /* isAwake */);
+        assertThat(mProvider.isAwake()).isTrue();
+        mListener.onDozeChanged(false /* isDozing */, false /* isAwake */);
+        assertThat(mProvider.isAwake()).isFalse();
+        mListener.onDozeChanged(true /* isDozing */, true /* isAwake */);
+        assertThat(mProvider.isAwake()).isTrue();
+        mListener.onDozeChanged(true /* isDozing */, false /* isAwake */);
+        assertThat(mProvider.isAwake()).isFalse();
+    }
+
+    @Test
     public void testSubscribesToAod() throws RemoteException {
-        final List<Boolean> expected = ImmutableList.of(true, false, true, true, false);
         final List<Boolean> actual = new ArrayList<>();
 
         mProvider.subscribe(mOpContext, ctx -> {
             assertThat(ctx).isSameInstanceAs(mOpContext);
+            assertThat(mProvider.isAod()).isEqualTo(ctx.isAod);
+            assertThat(mProvider.isAwake()).isFalse();
             actual.add(ctx.isAod);
         });
 
-        for (boolean v : expected) {
-            mListener.onDozeChanged(v);
+        for (boolean v : List.of(true, false, true, true, false, false)) {
+            mListener.onDozeChanged(v /* isDozing */, false /* isAwake */);
         }
 
-        assertThat(actual).containsExactlyElementsIn(expected).inOrder();
+        assertThat(actual).containsExactly(true, false, true, false).inOrder();
+    }
+
+    @Test
+    public void testSubscribesToAwake() throws RemoteException {
+        final List<Boolean> actual = new ArrayList<>();
+
+        mProvider.subscribe(mOpContext, ctx -> {
+            assertThat(ctx).isSameInstanceAs(mOpContext);
+            assertThat(ctx.isAod).isFalse();
+            assertThat(mProvider.isAod()).isFalse();
+            actual.add(mProvider.isAwake());
+        });
+
+        for (boolean v : List.of(true, false, true, true, false, false)) {
+            mListener.onDozeChanged(false /* isDozing */, v /* isAwake */);
+        }
+
+        assertThat(actual).containsExactly(true, false, true, false).inOrder();
     }
 
     @Test
@@ -124,13 +153,13 @@
         mProvider.subscribe(mOpContext, emptyConsumer);
         mProvider.unsubscribe(mOpContext);
 
-        mListener.onDozeChanged(true);
+        mListener.onDozeChanged(true /* isDozing */, false /* isAwake */);
 
         final Consumer<OperationContext> nonEmptyConsumer = mock(Consumer.class);
         mProvider.subscribe(mOpContext, nonEmptyConsumer);
-        mListener.onDozeChanged(false);
+        mListener.onDozeChanged(false /* isDozing */, false /* isAwake */);
         mProvider.unsubscribe(mOpContext);
-        mListener.onDozeChanged(true);
+        mListener.onDozeChanged(true /* isDozing */, false /* isAwake */);
 
         verify(emptyConsumer, never()).accept(any());
         verify(nonEmptyConsumer).accept(same(mOpContext));
@@ -171,7 +200,7 @@
 
     @Test
     public void testUpdate() throws RemoteException {
-        mListener.onDozeChanged(false);
+        mListener.onDozeChanged(false /* isDozing */, false /* isAwake */);
         OperationContext context = mProvider.updateContext(mOpContext, false /* crypto */);
 
         // default state when nothing has been set
@@ -186,7 +215,7 @@
             final int id = 40 + type;
             final boolean aod = (type & 1) == 0;
 
-            mListener.onDozeChanged(aod);
+            mListener.onDozeChanged(aod /* isDozing */, false /* isAwake */);
             mSessionListener.onSessionStarted(type, InstanceId.fakeInstanceId(id));
             context = mProvider.updateContext(mOpContext, false /* crypto */);
             assertThat(context).isSameInstanceAs(mOpContext);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
index 0b8e8ad..60dc2eb 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricLoggerTest.java
@@ -232,7 +232,7 @@
     public void testALSCallback() {
         mLogger = createLogger();
         final CallbackWithProbe<Probe> callback =
-                mLogger.createALSCallback(true /* startWithClient */);
+                mLogger.getAmbientLightProbe(true /* startWithClient */);
 
         callback.onClientStarted(mClient);
         verify(mSensorManager).registerListener(any(), any(), anyInt());
@@ -242,10 +242,37 @@
     }
 
     @Test
+    public void testALSCallbackWhenLogsDisabled() {
+        mLogger = createLogger();
+        mLogger.disableMetrics();
+        final CallbackWithProbe<Probe> callback =
+                mLogger.getAmbientLightProbe(true /* startWithClient */);
+
+        callback.onClientStarted(mClient);
+        verify(mSensorManager, never()).registerListener(any(), any(), anyInt());
+
+        callback.onClientFinished(mClient, true /* success */);
+        verify(mSensorManager, never()).unregisterListener(any(SensorEventListener.class));
+    }
+
+    @Test
+    public void testALSCallbackWhenDisabledAfterStarting() {
+        mLogger = createLogger();
+        final CallbackWithProbe<Probe> callback =
+                mLogger.getAmbientLightProbe(true /* startWithClient */);
+
+        callback.onClientStarted(mClient);
+        verify(mSensorManager).registerListener(any(), any(), anyInt());
+
+        mLogger.disableMetrics();
+        verify(mSensorManager).unregisterListener(any(SensorEventListener.class));
+    }
+
+    @Test
     public void testALSCallbackDoesNotStart() {
         mLogger = createLogger();
         final CallbackWithProbe<Probe> callback =
-                mLogger.createALSCallback(false /* startWithClient */);
+                mLogger.getAmbientLightProbe(false /* startWithClient */);
 
         callback.onClientStarted(mClient);
         callback.onClientFinished(mClient, true /* success */);
@@ -256,7 +283,7 @@
     public void testALSCallbackDestroyed() {
         mLogger = createLogger();
         final CallbackWithProbe<Probe> callback =
-                mLogger.createALSCallback(true /* startWithClient */);
+                mLogger.getAmbientLightProbe(true /* startWithClient */);
 
         callback.onClientStarted(mClient);
         callback.onClientFinished(mClient, false /* success */);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 45e3b437..eb131419 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -91,8 +91,7 @@
         mToken = new Binder();
         mScheduler = new BiometricScheduler(TAG, new Handler(TestableLooper.get(this).getLooper()),
                 BiometricScheduler.SENSOR_TYPE_UNKNOWN, null /* gestureAvailabilityTracker */,
-                mBiometricService, LOG_NUM_RECENT_OPERATIONS,
-                CoexCoordinator.getInstance());
+                mBiometricService, LOG_NUM_RECENT_OPERATIONS);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
deleted file mode 100644
index abf992b..0000000
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ /dev/null
@@ -1,573 +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.server.biometrics.sensors;
-
-import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FACE;
-import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_FP_OTHER;
-import static com.android.server.biometrics.sensors.BiometricScheduler.SENSOR_TYPE_UDFPS;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.hardware.biometrics.BiometricConstants;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.SmallTest;
-
-import com.android.server.biometrics.sensors.fingerprint.Udfps;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-import java.util.LinkedList;
-
-@Presubmit
-@SmallTest
-public class CoexCoordinatorTest {
-
-    @Rule
-    public final MockitoRule mockito = MockitoJUnit.rule();
-
-    @Mock
-    private CoexCoordinator.Callback mCallback;
-    @Mock
-    private CoexCoordinator.ErrorCallback mErrorCallback;
-    @Mock
-    private AuthenticationClient mFaceClient;
-    @Mock
-    private AuthenticationClient mFingerprintClient;
-    @Mock(extraInterfaces = {Udfps.class})
-    private AuthenticationClient mUdfpsClient;
-
-    private CoexCoordinator mCoexCoordinator;
-
-    @Before
-    public void setUp() {
-        mCoexCoordinator = CoexCoordinator.getInstance();
-        mCoexCoordinator.setAdvancedLogicEnabled(true);
-        mCoexCoordinator.setFaceHapticDisabledWhenNonBypass(true);
-        mCoexCoordinator.reset();
-    }
-
-    @Test
-    public void testBiometricPrompt_authSuccess() {
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */,
-                mFaceClient, mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testBiometricPrompt_authReject_whenNotLockedOut() {
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
-                mFaceClient, LockoutTracker.LOCKOUT_NONE, mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testBiometricPrompt_authReject_whenLockedOut() {
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
-                mFaceClient, LockoutTracker.LOCKOUT_TIMED, mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testBiometricPrompt_coex_success() {
-        testBiometricPrompt_coex_success(false /* twice */);
-    }
-
-    @Test
-    public void testBiometricPrompt_coex_successWithoutDouble() {
-        testBiometricPrompt_coex_success(true /* twice */);
-    }
-
-    private void testBiometricPrompt_coex_success(boolean twice) {
-        initFaceAndFingerprintForBiometricPrompt();
-        when(mFaceClient.wasAuthSuccessful()).thenReturn(true);
-        when(mUdfpsClient.wasAuthSuccessful()).thenReturn(twice, true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */,
-                mFaceClient, mCallback);
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */,
-                mUdfpsClient, mCallback);
-
-        if (twice) {
-            verify(mCallback, never()).sendHapticFeedback();
-        } else {
-            verify(mCallback).sendHapticFeedback();
-        }
-    }
-
-    @Test
-    public void testBiometricPrompt_coex_reject() {
-        initFaceAndFingerprintForBiometricPrompt();
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
-                mFaceClient, LockoutTracker.LOCKOUT_NONE, mCallback);
-
-        verify(mCallback, never()).sendHapticFeedback();
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
-                    mUdfpsClient, LockoutTracker.LOCKOUT_NONE, mCallback);
-
-        verify(mCallback).sendHapticFeedback();
-    }
-
-    @Test
-    public void testBiometricPrompt_coex_errorNoHaptics() {
-        initFaceAndFingerprintForBiometricPrompt();
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationError(mFaceClient,
-                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
-        mCoexCoordinator.onAuthenticationError(mUdfpsClient,
-                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
-
-        verify(mErrorCallback, never()).sendHapticFeedback();
-    }
-
-    private void initFaceAndFingerprintForBiometricPrompt() {
-        when(mFaceClient.isKeyguard()).thenReturn(false);
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-        when(mFaceClient.wasAuthAttempted()).thenReturn(true);
-        when(mUdfpsClient.isKeyguard()).thenReturn(false);
-        when(mUdfpsClient.isBiometricPrompt()).thenReturn(true);
-        when(mUdfpsClient.wasAuthAttempted()).thenReturn(true);
-    }
-
-    @Test
-    public void testKeyguard_faceAuthOnly_success() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */,
-                mFaceClient, mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testKeyguard_faceAuth_udfpsNotTouching_faceSuccess() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(false);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */,
-                mFaceClient, mCallback);
-        // Haptics tested in #testKeyguard_bypass_haptics. Let's leave this commented out (instead
-        // of removed) to keep this context.
-        // verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testKeyguard_faceAuthSuccess_nonBypass_udfpsRunning_noHaptics() {
-        testKeyguard_bypass_haptics(false /* bypassEnabled */,
-                true /* faceAccepted */,
-                false /* shouldReceiveHaptics */);
-    }
-
-    @Test
-    public void testKeyguard_faceAuthReject_nonBypass_udfpsRunning_noHaptics() {
-        testKeyguard_bypass_haptics(false /* bypassEnabled */,
-                false /* faceAccepted */,
-                false /* shouldReceiveHaptics */);
-    }
-
-    @Test
-    public void testKeyguard_faceAuthSuccess_bypass_udfpsRunning_haptics() {
-        testKeyguard_bypass_haptics(true /* bypassEnabled */,
-                true /* faceAccepted */,
-                true /* shouldReceiveHaptics */);
-    }
-
-    @Test
-    public void testKeyguard_faceAuthReject_bypass_udfpsRunning_haptics() {
-        testKeyguard_bypass_haptics(true /* bypassEnabled */,
-                false /* faceAccepted */,
-                true /* shouldReceiveHaptics */);
-    }
-
-    private void testKeyguard_bypass_haptics(boolean bypassEnabled, boolean faceAccepted,
-            boolean shouldReceiveHaptics) {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(false);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        if (faceAccepted) {
-            mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mFaceClient,
-                    mCallback);
-        } else {
-            mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient,
-                    LockoutTracker.LOCKOUT_NONE, mCallback);
-        }
-
-        if (shouldReceiveHaptics) {
-            verify(mCallback).sendHapticFeedback();
-        } else {
-            verify(mCallback, never()).sendHapticFeedback();
-        }
-
-        verify(mCallback).sendAuthenticationResult(eq(faceAccepted) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedWithinBounds() {
-        testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */,
-                0 /* udfpsRejectedAfterMs */);
-    }
-
-    @Test
-    public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsRejectedAfterBounds() {
-        testKeyguard_faceAuth_udfpsTouching_faceSuccess(false /* thenUdfpsAccepted */,
-                CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS + 1 /* udfpsRejectedAfterMs */);
-    }
-
-    @Test
-    public void testKeyguard_faceAuth_udfpsTouching_faceSuccess_thenUdfpsAccepted() {
-        testKeyguard_faceAuth_udfpsTouching_faceSuccess(true /* thenUdfpsAccepted */,
-                0 /* udfpsRejectedAfterMs */);
-    }
-
-    private void testKeyguard_faceAuth_udfpsTouching_faceSuccess(boolean thenUdfpsAccepted,
-            long udfpsRejectedAfterMs) {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true);
-        when(mUdfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        // For easier reading
-        final CoexCoordinator.Callback faceCallback = mCallback;
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mFaceClient,
-                faceCallback);
-        verify(faceCallback, never()).sendHapticFeedback();
-        verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
-        // CoexCoordinator requests the system to hold onto this AuthenticationClient until
-        // UDFPS result is known
-        verify(faceCallback, never()).handleLifecycleAfterAuth();
-
-        // Reset the mock
-        CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
-        assertEquals(1, mCoexCoordinator.mSuccessfulAuths.size());
-        assertEquals(mFaceClient, mCoexCoordinator.mSuccessfulAuths.get(0).mAuthenticationClient);
-        if (thenUdfpsAccepted) {
-            mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mUdfpsClient,
-                    udfpsCallback);
-            verify(udfpsCallback).sendHapticFeedback();
-            verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
-            verify(udfpsCallback).handleLifecycleAfterAuth();
-
-            verify(faceCallback).sendAuthenticationCanceled();
-
-            assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
-        } else {
-            mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, mUdfpsClient,
-                    LockoutTracker.LOCKOUT_NONE, udfpsCallback);
-            if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
-                verify(udfpsCallback, never()).sendHapticFeedback();
-
-                verify(faceCallback).sendHapticFeedback();
-                verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
-                verify(faceCallback).handleLifecycleAfterAuth();
-
-                assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
-            } else {
-                assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
-
-                verify(faceCallback, never()).sendHapticFeedback();
-                verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
-
-                verify(udfpsCallback).sendHapticFeedback();
-                verify(udfpsCallback)
-                        .sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
-                verify(udfpsCallback).handleLifecycleAfterAuth();
-            }
-        }
-    }
-
-    @Test
-    public void testKeyguard_udfpsAuthSuccess_whileFaceScanning() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, mUdfpsClient,
-                mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(true));
-        verify(mFaceClient).cancel();
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testKeyguard_faceRejectedWhenUdfpsTouching_thenUdfpsRejected() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mUdfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient,
-                LockoutTracker.LOCKOUT_NONE, mCallback);
-        verify(mCallback, never()).sendHapticFeedback();
-        verify(mCallback).handleLifecycleAfterAuth();
-
-        // BiometricScheduler removes the face authentication client after rejection
-        mCoexCoordinator.removeAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        // Then UDFPS rejected
-        CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
-        mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, mUdfpsClient,
-                LockoutTracker.LOCKOUT_NONE, udfpsCallback);
-        verify(udfpsCallback).sendHapticFeedback();
-        verify(udfpsCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
-        verify(mCallback, never()).sendHapticFeedback();
-    }
-
-    @Test
-    public void testKeyguard_udfpsRejected_thenFaceRejected_noKeyguardBypass() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(false); // TODO: also test "true" case
-        when(mUdfpsClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
-                mUdfpsClient, LockoutTracker.LOCKOUT_NONE, mCallback);
-        // Auth was attempted
-        when(mUdfpsClient.getState())
-                .thenReturn(AuthenticationClient.STATE_STARTED_PAUSED_ATTEMPTED);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).handleLifecycleAfterAuth();
-
-        // Then face rejected. Note that scheduler leaves UDFPS in the CoexCoordinator since
-        // unlike face, its lifecycle becomes "paused" instead of "finished".
-        CoexCoordinator.Callback faceCallback = mock(CoexCoordinator.Callback.class);
-        mCoexCoordinator.onAuthenticationRejected(1 /* currentTimeMillis */, mFaceClient,
-                LockoutTracker.LOCKOUT_NONE, faceCallback);
-        verify(faceCallback).sendHapticFeedback();
-        verify(faceCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
-        verify(mCallback).sendHapticFeedback();
-    }
-
-    @Test
-    public void testKeyguard_capacitiveAccepted_whenFaceScanning() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mFingerprintClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mFingerprintClient.isKeyguard()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, mFingerprintClient);
-
-        mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */,
-                mFingerprintClient, mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testKeyguard_capacitiveRejected_whenFaceScanning() {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mFingerprintClient.getState()).thenReturn(AuthenticationClient.STATE_STARTED);
-        when(mFingerprintClient.isKeyguard()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FP_OTHER, mFingerprintClient);
-
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */,
-                mFingerprintClient, LockoutTracker.LOCKOUT_NONE, mCallback);
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(false) /* addAuthTokenIfStrong */);
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testNonKeyguard_rejectAndNotLockedOut() {
-        when(mFaceClient.isKeyguard()).thenReturn(false);
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient,
-                LockoutTracker.LOCKOUT_NONE, mCallback);
-
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback).sendAuthenticationResult(eq(false));
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testNonKeyguard_rejectLockedOut() {
-        when(mFaceClient.isKeyguard()).thenReturn(false);
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.onAuthenticationRejected(0 /* currentTimeMillis */, mFaceClient,
-                LockoutTracker.LOCKOUT_TIMED, mCallback);
-
-        verify(mCallback).sendHapticFeedback();
-        verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
-        verify(mCallback).handleLifecycleAfterAuth();
-    }
-
-    @Test
-    public void testCleanupRunnable() {
-        LinkedList<CoexCoordinator.SuccessfulAuth> successfulAuths = mock(LinkedList.class);
-        CoexCoordinator.SuccessfulAuth auth = mock(CoexCoordinator.SuccessfulAuth.class);
-        CoexCoordinator.Callback callback = mock(CoexCoordinator.Callback.class);
-        CoexCoordinator.SuccessfulAuth.CleanupRunnable runnable =
-                new CoexCoordinator.SuccessfulAuth.CleanupRunnable(successfulAuths, auth, callback);
-        runnable.run();
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        verify(callback).handleLifecycleAfterAuth();
-        verify(successfulAuths).remove(eq(auth));
-    }
-
-    @Test
-    public void testBiometricPrompt_FaceError() {
-        when(mFaceClient.isBiometricPrompt()).thenReturn(true);
-        when(mFaceClient.wasAuthAttempted()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        mCoexCoordinator.onAuthenticationError(mFaceClient,
-                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
-        verify(mErrorCallback).sendHapticFeedback();
-    }
-
-    @Test
-    public void testKeyguard_faceAuthOnly_errorWhenBypassEnabled() {
-        testKeyguard_faceAuthOnly(true /* bypassEnabled */);
-    }
-
-    @Test
-    public void testKeyguard_faceAuthOnly_errorWhenBypassDisabled() {
-        testKeyguard_faceAuthOnly(false /* bypassEnabled */);
-    }
-
-    private void testKeyguard_faceAuthOnly(boolean bypassEnabled) {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
-        when(mFaceClient.wasAuthAttempted()).thenReturn(true);
-        when(mFaceClient.wasUserDetected()).thenReturn(true);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-
-        mCoexCoordinator.onAuthenticationError(mFaceClient,
-                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
-        verify(mErrorCallback).sendHapticFeedback();
-    }
-
-    @Test
-    public void testKeyguard_coex_faceErrorWhenBypassEnabled() {
-        testKeyguard_coex_faceError(true /* bypassEnabled */);
-    }
-
-    @Test
-    public void testKeyguard_coex_faceErrorWhenBypassDisabled() {
-        testKeyguard_coex_faceError(false /* bypassEnabled */);
-    }
-
-    private void testKeyguard_coex_faceError(boolean bypassEnabled) {
-        when(mFaceClient.isKeyguard()).thenReturn(true);
-        when(mFaceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
-        when(mFaceClient.wasAuthAttempted()).thenReturn(true);
-        when(mFaceClient.wasUserDetected()).thenReturn(true);
-        when(mUdfpsClient.isKeyguard()).thenReturn(true);
-        when(((Udfps) mUdfpsClient).isPointerDown()).thenReturn(false);
-
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, mFaceClient);
-        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, mUdfpsClient);
-
-        mCoexCoordinator.onAuthenticationError(mFaceClient,
-                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
-
-        if (bypassEnabled) {
-            verify(mErrorCallback).sendHapticFeedback();
-        } else {
-            verify(mErrorCallback, never()).sendHapticFeedback();
-        }
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
index 0df3028..0815fe5 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java
@@ -118,8 +118,7 @@
                                 TEST_SENSOR_ID,  mBiometricLogger, mBiometricContext,
                                 mUserStartedCallback, mStartOperationsFinish);
                     }
-                },
-                CoexCoordinator.getInstance());
+                });
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
index b60324e..518946a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/SensorTest.java
@@ -35,7 +35,6 @@
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.sensors.BiometricScheduler;
-import com.android.server.biometrics.sensors.CoexCoordinator;
 import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
@@ -91,8 +90,7 @@
                 null /* gestureAvailabilityDispatcher */,
                 mBiometricService,
                 () -> USER_ID,
-                mUserSwitchCallback,
-                CoexCoordinator.getInstance());
+                mUserSwitchCallback);
         mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()),
                 TAG, mScheduler, SENSOR_ID,
                 USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
index a149f3e..dea4d4f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClientTest.java
@@ -26,8 +26,8 @@
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.same;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -96,6 +96,7 @@
             InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
     @Rule
     public final MockitoRule mockito = MockitoJUnit.rule();
+
     @Mock
     private ISession mHal;
     @Mock
@@ -137,7 +138,7 @@
     @Before
     public void setup() {
         mContext.addMockSystemService(BiometricManager.class, mBiometricManager);
-        when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i ->
+        when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
                 new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
         when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
                 i -> i.getArgument(0));
@@ -213,21 +214,41 @@
     }
 
     @Test
-    public void luxProbeWhenFingerDown() throws RemoteException {
+    public void luxProbeWhenAwake() throws RemoteException {
+        when(mBiometricContext.isAwake()).thenReturn(false, true, false);
+        when(mBiometricContext.isAod()).thenReturn(false);
         final FingerprintAuthenticationClient client = createClient();
         client.start(mCallback);
 
-        client.onPointerDown(TOUCH_X, TOUCH_Y, TOUCH_MAJOR, TOUCH_MINOR);
-        verify(mLuxProbe).enable();
+        verify(mHal).authenticateWithContext(eq(OP_ID), mOperationContextCaptor.capture());
+        OperationContext opContext = mOperationContextCaptor.getValue();
+        verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture());
 
-        client.onAcquired(2, 0);
+        mContextInjector.getValue().accept(opContext);
+        verify(mLuxProbe, never()).enable();
+
+        reset(mLuxProbe);
+        mContextInjector.getValue().accept(opContext);
+        verify(mLuxProbe).enable();
         verify(mLuxProbe, never()).disable();
 
-        client.onPointerUp();
+        mContextInjector.getValue().accept(opContext);
         verify(mLuxProbe).disable();
+    }
 
-        client.onPointerDown(TOUCH_X, TOUCH_Y, TOUCH_MAJOR, TOUCH_MINOR);
-        verify(mLuxProbe, times(2)).enable();
+    @Test
+    public void luxProbeDisabledOnAod() throws RemoteException {
+        when(mBiometricContext.isAwake()).thenReturn(false);
+        when(mBiometricContext.isAod()).thenReturn(true);
+        final FingerprintAuthenticationClient client = createClient();
+        client.start(mCallback);
+
+        verify(mHal).authenticateWithContext(eq(OP_ID), mOperationContextCaptor.capture());
+        OperationContext opContext = mOperationContextCaptor.getValue();
+        verify(mBiometricContext).subscribe(eq(opContext), mContextInjector.capture());
+
+        mContextInjector.getValue().accept(opContext);
+        verify(mLuxProbe, never()).enable();
     }
 
     @Test
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 f77eb0b..92e1f27a 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
@@ -64,6 +64,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.ArrayList;
 import java.util.function.Consumer;
 
 @Presubmit
@@ -119,7 +120,7 @@
 
     @Before
     public void setup() {
-        when(mBiometricLogger.createALSCallback(anyBoolean())).thenAnswer(i ->
+        when(mBiometricLogger.getAmbientLightProbe(anyBoolean())).thenAnswer(i ->
                 new CallbackWithProbe<>(mLuxProbe, i.getArgument(0)));
         when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
                 i -> i.getArgument(0));
@@ -196,21 +197,22 @@
     }
 
     @Test
-    public void luxProbeWhenFingerDown() throws RemoteException {
+    public void luxProbeWhenStarted() throws RemoteException {
         final FingerprintEnrollClient client = createClient();
         client.start(mCallback);
 
-        client.onPointerDown(TOUCH_X, TOUCH_Y, TOUCH_MAJOR, TOUCH_MINOR);
         verify(mLuxProbe).enable();
 
         client.onAcquired(2, 0);
-        verify(mLuxProbe, never()).disable();
-
         client.onPointerUp();
-        verify(mLuxProbe).disable();
-
         client.onPointerDown(TOUCH_X, TOUCH_Y, TOUCH_MAJOR, TOUCH_MINOR);
-        verify(mLuxProbe, times(2)).enable();
+        verify(mLuxProbe, never()).disable();
+        verify(mLuxProbe, never()).destroy();
+
+        client.onEnrollResult(new Fingerprint("f", 30 /* fingerId */, 14 /* deviceId */),
+                0 /* remaining */);
+
+        verify(mLuxProbe).destroy();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
index e1a4a2d..ff636c8 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/SensorTest.java
@@ -35,7 +35,6 @@
 import com.android.server.biometrics.log.BiometricContext;
 import com.android.server.biometrics.log.BiometricLogger;
 import com.android.server.biometrics.sensors.BiometricScheduler;
-import com.android.server.biometrics.sensors.CoexCoordinator;
 import com.android.server.biometrics.sensors.LockoutCache;
 import com.android.server.biometrics.sensors.LockoutResetDispatcher;
 import com.android.server.biometrics.sensors.LockoutTracker;
@@ -91,8 +90,7 @@
                 null /* gestureAvailabilityDispatcher */,
                 mBiometricService,
                 () -> USER_ID,
-                mUserSwitchCallback,
-                CoexCoordinator.getInstance());
+                mUserSwitchCallback);
         mHalCallback = new Sensor.HalSessionCallback(mContext, new Handler(mLooper.getLooper()),
                 TAG, mScheduler, SENSOR_ID,
                 USER_ID, mLockoutCache, mLockoutResetDispatcher, mHalSessionCallback);
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 a7ca083..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);
     }
 
@@ -6724,55 +6721,51 @@
     }
 
     @Test
-    public void testEnforceCallerCanRequestDeviceIdAttestation_deviceOwnerCaller()
+    public void testHasDeviceIdAccessUnchecked_deviceOwnerCaller()
             throws Exception {
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
         setupDeviceOwner();
         configureContextForAccess(mContext, false);
 
         // Device owner should be allowed to request Device ID attestation.
-        dpms.enforceCallerCanRequestDeviceIdAttestation(dpms.getCallerIdentity(admin1));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                admin1.getPackageName(),
+                DpmMockContext.CALLER_SYSTEM_USER_UID)).isTrue();
 
-        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
         // Another package must not be allowed to request Device ID attestation.
-        assertExpectException(SecurityException.class, null,
-                () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                        dpms.getCallerIdentity(null, admin2.getPackageName())));
-
-        // Another component that is not the admin must not be allowed to request Device ID
-        // attestation.
-        assertExpectException(SecurityException.class, null,
-                () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                        dpms.getCallerIdentity(admin2)));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                DpmMockContext.ANOTHER_PACKAGE_NAME,
+                DpmMockContext.CALLER_SYSTEM_USER_UID)).isFalse();
     }
 
     @Test
-    public void testEnforceCallerCanRequestDeviceIdAttestation_profileOwnerCaller()
+    public void testHasDeviceIdAccessUnchecked_profileOwnerCaller()
             throws Exception {
         configureContextForAccess(mContext, false);
 
         // Make sure a security exception is thrown if the device has no profile owner.
-        assertExpectException(SecurityException.class, null,
-                () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                        dpms.getCallerIdentity(admin1)));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                admin1.getPackageName(),
+                DpmMockContext.CALLER_UID)).isFalse();
 
         setupProfileOwner();
         configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
 
         // The profile owner is allowed to request Device ID attestation.
-        mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
-        dpms.enforceCallerCanRequestDeviceIdAttestation(dpms.getCallerIdentity(admin1));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                admin1.getPackageName(),
+                DpmMockContext.CALLER_UID)).isTrue();
 
         // But not another package.
-        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
-        assertExpectException(SecurityException.class, null,
-                () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                        dpms.getCallerIdentity(null, admin2.getPackageName())));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                DpmMockContext.ANOTHER_PACKAGE_NAME,
+                DpmMockContext.CALLER_UID)).isFalse();
 
         // Or another component which is not the admin.
-        assertExpectException(SecurityException.class, null,
-                () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                        dpms.getCallerIdentity(admin2, admin2.getPackageName())));
+        mContext.binder.callingUid = DpmMockContext.ANOTHER_UID;
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                admin1.getPackageName(),
+                DpmMockContext.ANOTHER_UID)).isFalse();
     }
 
     public void runAsDelegatedCertInstaller(DpmRunnable action) throws Exception {
@@ -6788,7 +6781,7 @@
     }
 
     @Test
-    public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCaller() throws Exception {
+    public void testHasDeviceIdAccessUnchecked_delegateCaller() throws Exception {
         setupProfileOwner();
         markDelegatedCertInstallerAsInstalled();
 
@@ -6800,15 +6793,19 @@
         configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE);
 
         // Make sure that the profile owner can still request Device ID attestation.
-        mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
-        dpms.enforceCallerCanRequestDeviceIdAttestation(dpms.getCallerIdentity(admin1));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                admin1.getPackageName(),
+                DpmMockContext.CALLER_UID)).isTrue();
 
-        runAsDelegatedCertInstaller(dpm -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                dpms.getCallerIdentity(null, DpmMockContext.DELEGATE_PACKAGE_NAME)));
+        runAsDelegatedCertInstaller(dpm -> assertThat(
+                dpms.hasDeviceIdAccessUnchecked(
+                        DpmMockContext.DELEGATE_PACKAGE_NAME,
+                        UserHandle.getUid(CALLER_USER_HANDLE,
+                                DpmMockContext.DELEGATE_CERT_INSTALLER_UID))).isTrue());
     }
 
     @Test
-    public void testEnforceCallerCanRequestDeviceIdAttestation_delegateCallerWithoutPermissions()
+    public void testHasDeviceIdAccessUnchecked_delegateCallerWithoutPermissions()
             throws Exception {
         setupProfileOwner();
         markDelegatedCertInstallerAsInstalled();
@@ -6818,14 +6815,14 @@
                 dpm -> dpm.setDelegatedScopes(admin1, DpmMockContext.DELEGATE_PACKAGE_NAME,
                         Arrays.asList(DELEGATION_CERT_INSTALL)));
 
-        assertExpectException(SecurityException.class, null,
-                () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                        dpms.getCallerIdentity(admin1)));
+        assertThat(dpms.hasDeviceIdAccessUnchecked(
+                admin1.getPackageName(),
+                DpmMockContext.CALLER_UID)).isFalse();
 
         runAsDelegatedCertInstaller(dpm -> {
-            assertExpectException(SecurityException.class, /* messageRegex= */ null,
-                    () -> dpms.enforceCallerCanRequestDeviceIdAttestation(
-                            dpms.getCallerIdentity(null, DpmMockContext.DELEGATE_PACKAGE_NAME)));
+            assertThat(dpms.hasDeviceIdAccessUnchecked(
+                    DpmMockContext.DELEGATE_PACKAGE_NAME,
+                    DpmMockContext.CALLER_UID)).isFalse();
         });
     }
 
@@ -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/DisplayDeviceConfigTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
index 261b882..66420ad 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -86,23 +86,22 @@
         assertEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLightDebounce(), 2000);
         assertEquals(mDisplayDeviceConfig.getAutoBrightnessDarkeningLightDebounce(), 1000);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
-                float[]{50.0f, 80.0f}, 0.0f);
+                float[]{0.0f, 50.0f, 80.0f}, 0.0f);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
-                float[]{45.0f, 75.0f}, 0.0f);
+                float[]{45.32f, 75.43f}, 0.0f);
         // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
     }
 
     @Test
-    public void testConfigValuesFromDeviceConfig() {
-        setupDisplayDeviceConfigFromDeviceConfigFile();
-        assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
-                float[]{0.0f, 110.0f, 500.0f}, 0.0f);
+    public void testConfigValuesFromConfigResource() {
+        setupDisplayDeviceConfigFromConfigResourceFile();
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
                 float[]{2.0f, 200.0f, 600.0f}, 0.0f);
+        assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
+                float[]{0.0f, 0.0f, 110.0f, 500.0f}, 0.0f);
         // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
-
     }
 
     private String getContent() {
@@ -128,11 +127,11 @@
                 +       "<displayBrightnessMapping>\n"
                 +            "<displayBrightnessPoint>\n"
                 +                "<lux>50</lux>\n"
-                +                "<nits>45</nits>\n"
+                +                "<nits>45.32</nits>\n"
                 +            "</displayBrightnessPoint>\n"
                 +            "<displayBrightnessPoint>\n"
                 +                "<lux>80</lux>\n"
-                +                "<nits>75</nits>\n"
+                +                "<nits>75.43</nits>\n"
                 +            "</displayBrightnessPoint>\n"
                 +       "</displayBrightnessMapping>\n"
                 +   "</autoBrightness>\n"
@@ -214,7 +213,7 @@
         mDisplayDeviceConfig.initFromFile(tempFile.toFile());
     }
 
-    private void setupDisplayDeviceConfigFromDeviceConfigFile() {
+    private void setupDisplayDeviceConfigFromConfigResourceFile() {
         TypedArray screenBrightnessNits = createFloatTypedArray(new float[]{2.0f, 250.0f, 650.0f});
         when(mResources.obtainTypedArray(
                 com.android.internal.R.array.config_screenBrightnessNits))
@@ -237,9 +236,8 @@
         when(mResources.obtainTypedArray(
                 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
                 .thenReturn(screenBrightnessLevelNits);
-        TypedArray screenBrightnessLevelLux = createFloatTypedArray(new
-                float[]{0.0f, 110.0f, 500.0f});
-        when(mResources.obtainTypedArray(
+        int[] screenBrightnessLevelLux = new int[]{0, 110, 500};
+        when(mResources.getIntArray(
                 com.android.internal.R.array.config_autoBrightnessLevels))
                 .thenReturn(screenBrightnessLevelLux);
 
diff --git a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
index 74d2e0f..0efd296 100644
--- a/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/dreams/DreamServiceTest.java
@@ -16,7 +16,8 @@
 
 package com.android.server.dreams;
 
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertFalse;
 
 import android.content.ComponentName;
@@ -35,21 +36,36 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class DreamServiceTest {
+    private static final String TEST_PACKAGE_NAME = "com.android.frameworks.servicestests";
+
     @Test
     public void testMetadataParsing() throws PackageManager.NameNotFoundException {
-        final String testPackageName = "com.android.frameworks.servicestests";
         final String testDreamClassName = "com.android.server.dreams.TestDreamService";
-        final String testSettingsActivity = "com.android.server.dreams/.TestDreamSettingsActivity";
+        final String testSettingsActivity =
+                "com.android.frameworks.servicestests/.TestDreamSettingsActivity";
+        final DreamService.DreamMetadata metadata = getDreamMetadata(testDreamClassName);
 
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
-        final ServiceInfo si = context.getPackageManager().getServiceInfo(
-                new ComponentName(testPackageName, testDreamClassName),
-                PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
-        final DreamService.DreamMetadata metadata = DreamService.getDreamMetadata(context, si);
-
-        assertEquals(0, metadata.settingsActivity.compareTo(
-                ComponentName.unflattenFromString(testSettingsActivity)));
+        assertThat(metadata.settingsActivity).isEqualTo(
+                ComponentName.unflattenFromString(testSettingsActivity));
         assertFalse(metadata.showComplications);
     }
+
+    @Test
+    public void testMetadataParsing_invalidSettingsActivity()
+            throws PackageManager.NameNotFoundException {
+        final String testDreamClassName =
+                "com.android.server.dreams.TestDreamServiceWithInvalidSettings";
+        final DreamService.DreamMetadata metadata = getDreamMetadata(testDreamClassName);
+
+        assertThat(metadata.settingsActivity).isNull();
+    }
+
+    private DreamService.DreamMetadata getDreamMetadata(String dreamClassName)
+            throws PackageManager.NameNotFoundException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final ServiceInfo si = context.getPackageManager().getServiceInfo(
+                new ComponentName(TEST_PACKAGE_NAME, dreamClassName),
+                PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA));
+        return DreamService.getDreamMetadata(context, si);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt b/services/tests/servicestests/src/com/android/server/dreams/TestDreamServiceWithInvalidSettings.java
similarity index 70%
copy from packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
copy to services/tests/servicestests/src/com/android/server/dreams/TestDreamServiceWithInvalidSettings.java
index 88e227b..5c7d02f 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardViewMediatorLog.kt
+++ b/services/tests/servicestests/src/com/android/server/dreams/TestDreamServiceWithInvalidSettings.java
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.log.dagger
+package com.android.server.dreams;
 
-import javax.inject.Qualifier
+import android.service.dreams.DreamService;
 
-/** A [com.android.systemui.log.LogBuffer] for KeyguardViewMediator. */
-@Qualifier
-annotation class KeyguardViewMediatorLog
\ No newline at end of file
+/**
+ * Dream service implementation for unit testing, where the settings activity is invalid.
+ */
+public class TestDreamServiceWithInvalidSettings extends DreamService {
+}
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/logcat/LogcatManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/logcat/LogcatManagerServiceTest.java
index f330017..6a27f39 100644
--- a/services/tests/servicestests/src/com/android/server/logcat/LogcatManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/logcat/LogcatManagerServiceTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.logcat;
 
+import static android.os.Process.INVALID_UID;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -28,6 +30,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
 import android.os.ILogd;
 import android.os.Looper;
 import android.os.UserHandle;
@@ -69,6 +72,8 @@
     @Mock
     private ActivityManagerInternal mActivityManagerInternalMock;
     @Mock
+    private PackageManager mPackageManagerMock;
+    @Mock
     private ILogd mLogdMock;
 
     private LogcatManagerService mService;
@@ -81,10 +86,17 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
+        when(mActivityManagerInternalMock.getInstrumentationSourceUid(anyInt()))
+                .thenReturn(INVALID_UID);
+
         mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         mClock = new OffsettableClock.Stopped();
         mTestLooper = new TestLooper(mClock::now);
-
+        when(mContextSpy.getPackageManager()).thenReturn(mPackageManagerMock);
+        when(mPackageManagerMock.getPackagesForUid(APP1_UID)).thenReturn(
+                new String[]{APP1_PACKAGE_NAME});
+        when(mPackageManagerMock.getPackagesForUid(APP2_UID)).thenReturn(
+                new String[]{APP2_PACKAGE_NAME});
         when(mActivityManagerInternalMock.getPackageNameByPid(APP1_PID)).thenReturn(
                 APP1_PACKAGE_NAME);
         when(mActivityManagerInternalMock.getPackageNameByPid(APP2_PID)).thenReturn(
@@ -136,6 +148,20 @@
     }
 
     @Test
+    public void test_RequestFromBackground_ApprovedIfInstrumented() throws Exception {
+        when(mActivityManagerInternalMock.getInstrumentationSourceUid(APP1_UID))
+                .thenReturn(APP1_UID);
+        when(mActivityManagerInternalMock.getUidProcessState(APP1_UID)).thenReturn(
+                ActivityManager.PROCESS_STATE_RECEIVER);
+        mService.getBinderService().startThread(APP1_UID, APP1_GID, APP1_PID, FD1);
+        mTestLooper.dispatchAll();
+
+        verify(mLogdMock).approve(APP1_UID, APP1_GID, APP1_PID, FD1);
+        verify(mLogdMock, never()).decline(APP1_UID, APP1_GID, APP1_PID, FD1);
+        verify(mContextSpy, never()).startActivityAsUser(any(), any());
+    }
+
+    @Test
     public void test_RequestFromForegroundService_DeclinedWithoutPrompt() throws Exception {
         when(mActivityManagerInternalMock.getUidProcessState(APP1_UID)).thenReturn(
                 ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
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 0f2fe44..3bcde6a 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -75,6 +75,7 @@
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
 import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
 import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
+import static com.android.server.net.NetworkPolicyManagerService.normalizeTemplate;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -167,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;
@@ -2030,6 +2031,18 @@
                 METERED_NO, actualPolicy.template.getMeteredness());
     }
 
+    @Test
+    public void testNormalizeTemplate_duplicatedMergedImsiList() {
+        final NetworkTemplate template = new NetworkTemplate.Builder(MATCH_CARRIER)
+                .setSubscriberIds(Set.of(TEST_IMSI)).build();
+        final String[] mergedImsiGroup = new String[] {TEST_IMSI, TEST_IMSI};
+        final ArrayList<String[]> mergedList = new ArrayList<>();
+        mergedList.add(mergedImsiGroup);
+        // Verify the duplicated items in the merged IMSI list won't crash the system.
+        final NetworkTemplate result = normalizeTemplate(template, mergedList);
+        assertEquals(template, result);
+    }
+
     private String formatBlockedStateError(int uid, int rule, boolean metered,
             boolean backgroundRestricted) {
         return String.format(
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/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index b1ad8ec..e04edc6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import static android.os.UserManager.DISALLOW_BLUETOOTH;
 import static android.os.UserManager.DISALLOW_USER_SWITCH;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -40,6 +41,7 @@
 import com.android.server.LocalServices;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -174,6 +176,21 @@
     }
 
     @Test
+    public void testSetUserRestrictionWithIncorrectID() throws Exception {
+        int incorrectId = 1;
+        while (mUserManagerService.userExists(incorrectId)) {
+            incorrectId++;
+        }
+        try {
+            mUserManagerService.setUserRestriction(DISALLOW_BLUETOOTH, true, incorrectId);
+            Assert.fail();
+        } catch (IllegalArgumentException e) {
+            //Exception is expected to be thrown if user ID does not exist.
+            // IllegalArgumentException thrown means this test is successful.
+        }
+    }
+
+    @Test
     public void assertIsUserSwitcherEnabledOnMultiUserSettings() throws Exception {
         int userId = ActivityManager.getCurrentUser();
         resetUserSwitcherEnabled();
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/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index f1f423d..f6852d8 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -992,6 +992,40 @@
     }
 
     @Test
+    public void testInattentiveSleep_warningStaysWhenDreaming() {
+        setMinimumScreenOffTimeoutConfig(5);
+        setAttentiveWarningDuration(70);
+        setAttentiveTimeout(100);
+        createService();
+        startSystem();
+        advanceTime(50);
+        verify(mInattentiveSleepWarningControllerMock, atLeastOnce()).show();
+        when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(true);
+
+        forceDream();
+        when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+
+        advanceTime(10);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
+        verify(mInattentiveSleepWarningControllerMock, never()).dismiss(anyBoolean());
+    }
+
+    @Test
+    public void testInattentiveSleep_warningNotShownWhenSleeping() {
+        setMinimumScreenOffTimeoutConfig(5);
+        setAttentiveWarningDuration(70);
+        setAttentiveTimeout(100);
+        createService();
+        startSystem();
+
+        advanceTime(10);
+        forceSleep();
+
+        advanceTime(50);
+        verify(mInattentiveSleepWarningControllerMock, never()).show();
+    }
+
+    @Test
     public void testInattentiveSleep_noWarningShownIfInattentiveSleepDisabled() {
         setAttentiveTimeout(-1);
         createService();
diff --git a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
index 5c934852..d5b923a 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/BatteryStatsHistoryTest.java
@@ -16,11 +16,18 @@
 
 package com.android.server.power.stats;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.os.BatteryManager;
+import android.os.BatteryStats;
+import android.os.BatteryStats.HistoryItem;
+import android.os.BatteryStats.MeasuredEnergyDetails;
 import android.os.Parcel;
 import android.util.Log;
 
@@ -28,15 +35,21 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.os.BatteryStatsHistory;
+import com.android.internal.os.BatteryStatsHistoryIterator;
 import com.android.internal.os.Clock;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
 import java.io.File;
 import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -51,6 +64,11 @@
     private File mSystemDir;
     private File mHistoryDir;
     private final Clock mClock = new MockClock();
+    private BatteryStatsHistory mHistory;
+    @Mock
+    private BatteryStatsHistory.TraceDelegate mTracer;
+    @Mock
+    private BatteryStatsHistory.HistoryStepDetailsCalculator mStepDetailsCalculator;
 
     @Before
     public void setUp() {
@@ -65,59 +83,117 @@
             }
         }
         mHistoryDir.delete();
+        mHistory = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
+                mStepDetailsCalculator, mClock, mTracer);
+
+        when(mStepDetailsCalculator.getHistoryStepDetails())
+                .thenReturn(new BatteryStats.HistoryStepDetails());
+    }
+
+    @Test
+    public void testAtraceBinaryState1() {
+        mHistory.forceRecordAllHistory();
+
+        InOrder inOrder = Mockito.inOrder(mTracer);
+        Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+        mHistory.recordStateStartEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG);
+        mHistory.recordStateStopEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG);
+        mHistory.recordStateStartEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG);
+
+        inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1);
+        inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 0);
+        inOrder.verify(mTracer).traceCounter("battery_stats.mobile_radio", 1);
+    }
+
+    @Test
+    public void testAtraceBinaryState2() {
+        mHistory.forceRecordAllHistory();
+
+        InOrder inOrder = Mockito.inOrder(mTracer);
+        Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+        mHistory.recordState2StartEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG);
+        mHistory.recordState2StopEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG);
+        mHistory.recordState2StartEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), HistoryItem.STATE2_WIFI_ON_FLAG);
+
+        inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1);
+        inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 0);
+        inOrder.verify(mTracer).traceCounter("battery_stats.wifi", 1);
+    }
+
+    @Test
+    public void testAtraceNumericalState() {
+        mHistory.forceRecordAllHistory();
+
+        InOrder inOrder = Mockito.inOrder(mTracer);
+        Mockito.when(mTracer.tracingEnabled()).thenReturn(true);
+
+        mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), 1);
+        mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), 2);
+        mHistory.recordDataConnectionTypeChangeEvent(mClock.elapsedRealtime(),
+                mClock.uptimeMillis(), 3);
+
+        inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 1);
+        inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 2);
+        inOrder.verify(mTracer).traceCounter("battery_stats.data_conn", 3);
     }
 
     @Test
     public void testConstruct() {
-        BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
-                null, mClock);
-        createActiveFile(history);
-        verifyFileNumbers(history, Arrays.asList(0));
-        verifyActiveFile(history, "0.bin");
+        createActiveFile(mHistory);
+        verifyFileNumbers(mHistory, Arrays.asList(0));
+        verifyActiveFile(mHistory, "0.bin");
     }
 
     @Test
     public void testStartNextFile() {
-        BatteryStatsHistory history = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
-                null, mClock);
         List<Integer> fileList = new ArrayList<>();
         fileList.add(0);
-        createActiveFile(history);
+        createActiveFile(mHistory);
 
         // create file 1 to 31.
         for (int i = 1; i < 32; i++) {
             fileList.add(i);
-            history.startNextFile();
-            createActiveFile(history);
-            verifyFileNumbers(history, fileList);
-            verifyActiveFile(history, i + ".bin");
+            mHistory.startNextFile();
+            createActiveFile(mHistory);
+            verifyFileNumbers(mHistory, fileList);
+            verifyActiveFile(mHistory, i + ".bin");
         }
 
         // create file 32
-        history.startNextFile();
-        createActiveFile(history);
+        mHistory.startNextFile();
+        createActiveFile(mHistory);
         fileList.add(32);
         fileList.remove(0);
         // verify file 0 is deleted.
         verifyFileDeleted("0.bin");
-        verifyFileNumbers(history, fileList);
-        verifyActiveFile(history, "32.bin");
+        verifyFileNumbers(mHistory, fileList);
+        verifyActiveFile(mHistory, "32.bin");
 
         // create file 33
-        history.startNextFile();
-        createActiveFile(history);
+        mHistory.startNextFile();
+        createActiveFile(mHistory);
         // verify file 1 is deleted
         fileList.add(33);
         fileList.remove(0);
         verifyFileDeleted("1.bin");
-        verifyFileNumbers(history, fileList);
-        verifyActiveFile(history, "33.bin");
+        verifyFileNumbers(mHistory, fileList);
+        verifyActiveFile(mHistory, "33.bin");
 
-        assertEquals(0, history.getHistoryUsedSize());
+        assertEquals(0, mHistory.getHistoryUsedSize());
 
         // create a new BatteryStatsHistory object, it will pick up existing history files.
         BatteryStatsHistory history2 = new BatteryStatsHistory(mHistoryBuffer, mSystemDir, 32, 1024,
-                null, mClock);
+                null, mClock, mTracer);
         // verify constructor can pick up all files from file system.
         verifyFileNumbers(history2, fileList);
         verifyActiveFile(history2, "33.bin");
@@ -168,4 +244,74 @@
             Log.e(TAG, "Error creating history file " + file.getPath(), e);
         }
     }
+
+    @Test
+    public void testRecordMeasuredEnergyDetails() {
+        mHistory.forceRecordAllHistory();
+        mHistory.startRecordingHistory(0, 0, /* reset */ true);
+        mHistory.setBatteryState(true /* charging */, BatteryManager.BATTERY_STATUS_CHARGING, 80,
+                1234);
+
+        MeasuredEnergyDetails details = new MeasuredEnergyDetails();
+        MeasuredEnergyDetails.EnergyConsumer consumer1 =
+                new MeasuredEnergyDetails.EnergyConsumer();
+        consumer1.type = 42;
+        consumer1.ordinal = 0;
+        consumer1.name = "A";
+
+        MeasuredEnergyDetails.EnergyConsumer consumer2 =
+                new MeasuredEnergyDetails.EnergyConsumer();
+        consumer2.type = 777;
+        consumer2.ordinal = 0;
+        consumer2.name = "B/0";
+
+        MeasuredEnergyDetails.EnergyConsumer consumer3 =
+                new MeasuredEnergyDetails.EnergyConsumer();
+        consumer3.type = 777;
+        consumer3.ordinal = 1;
+        consumer3.name = "B/1";
+
+        MeasuredEnergyDetails.EnergyConsumer consumer4 =
+                new MeasuredEnergyDetails.EnergyConsumer();
+        consumer4.type = 314;
+        consumer4.ordinal = 1;
+        consumer4.name = "C";
+
+        details.consumers =
+                new MeasuredEnergyDetails.EnergyConsumer[]{consumer1, consumer2, consumer3,
+                        consumer4};
+        details.chargeUC = new long[details.consumers.length];
+        for (int i = 0; i < details.chargeUC.length; i++) {
+            details.chargeUC[i] = 100L * i;
+        }
+        details.chargeUC[3] = BatteryStats.POWER_DATA_UNAVAILABLE;
+
+        mHistory.recordMeasuredEnergyDetails(200, 200, details);
+
+        BatteryStatsHistoryIterator iterator = mHistory.iterate();
+        BatteryStats.HistoryItem item = new BatteryStats.HistoryItem();
+        assertThat(iterator.next(item)).isTrue(); // First item contains current time only
+
+        assertThat(iterator.next(item)).isTrue();
+
+        String dump = toString(item, /* checkin */ false);
+        assertThat(dump).contains("+200ms");
+        assertThat(dump).contains("ext=E");
+        assertThat(dump).contains("Energy: A=0 B/0=100 B/1=200");
+        assertThat(dump).doesNotContain("C=");
+
+        String checkin = toString(item, /* checkin */ true);
+        assertThat(checkin).contains("XE");
+        assertThat(checkin).contains("A=0,B/0=100,B/1=200");
+        assertThat(checkin).doesNotContain("C=");
+    }
+
+    private String toString(BatteryStats.HistoryItem item, boolean checkin) {
+        BatteryStats.HistoryPrinter printer = new BatteryStats.HistoryPrinter();
+        StringWriter writer = new StringWriter();
+        PrintWriter pw = new PrintWriter(writer);
+        printer.printNextItem(pw, item, 0, checkin, /* verbose */ true);
+        pw.flush();
+        return writer.toString();
+    }
 }
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/power/stats/MeasuredEnergySnapshotTest.java b/services/tests/servicestests/src/com/android/server/power/stats/MeasuredEnergySnapshotTest.java
index 8a0f924..122f7eb 100644
--- a/services/tests/servicestests/src/com/android/server/power/stats/MeasuredEnergySnapshotTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/stats/MeasuredEnergySnapshotTest.java
@@ -26,6 +26,7 @@
 import android.hardware.power.stats.EnergyConsumerAttribution;
 import android.hardware.power.stats.EnergyConsumerResult;
 import android.hardware.power.stats.EnergyConsumerType;
+import android.os.BatteryStats;
 import android.util.SparseArray;
 import android.util.SparseLongArray;
 
@@ -236,6 +237,17 @@
         assertEquals(0, snapshot.getOtherOrdinalNames().length);
     }
 
+    @Test
+    public void getMeasuredEnergyDetails() {
+        final MeasuredEnergySnapshot snapshot = new MeasuredEnergySnapshot(ALL_ID_CONSUMER_MAP);
+        snapshot.updateAndGetDelta(RESULTS_0, VOLTAGE_0);
+        MeasuredEnergyDeltaData delta = snapshot.updateAndGetDelta(RESULTS_1, VOLTAGE_1);
+        BatteryStats.MeasuredEnergyDetails details = snapshot.getMeasuredEnergyDetails(delta);
+        assertThat(details.consumers).hasLength(4);
+        assertThat(details.chargeUC).isEqualTo(new long[]{2667, 3200000, 0, 0});
+        assertThat(details.toString()).isEqualTo("DISPLAY=2667 HPU=3200000 GPU=0 IPU &_=0");
+    }
+
     private static EnergyConsumer createEnergyConsumer(int id, int ord, byte type, String name) {
         final EnergyConsumer ec = new EnergyConsumer();
         ec.id = id;
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/VibratorManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index 8b512e9..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;
@@ -102,6 +101,7 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.time.Duration;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -120,6 +120,10 @@
 public class VibratorManagerServiceTest {
 
     private static final int TEST_TIMEOUT_MILLIS = 1_000;
+    // Time to allow for a cancellation to complete (notably including system ramp down), but not so
+    // long that tests easily get really slow or flaky. If a vibration is close to this, it should
+    // be cancelled in the body of the individual test.
+    private static final int CLEANUP_TIMEOUT_MILLIS = 100;
     private static final int UID = Process.ROOT_UID;
     private static final int VIRTUAL_DISPLAY_ID = 1;
     private static final String PACKAGE_NAME = "package";
@@ -165,6 +169,7 @@
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
 
+    private VibratorManagerService mService;
     private Context mContextSpy;
     private TestLooper mTestLooper;
     private FakeVibrator mVibrator;
@@ -229,8 +234,27 @@
 
     @After
     public void tearDown() throws Exception {
+        if (mService != null) {
+            // Wait until all vibrators have stopped vibrating, with a bit of flexibility for tests
+            // that just do a click or have cancelled at the end (waiting for ramp-down).
+            //
+            // Note: if a test is flaky here, check whether a VibrationEffect duration is close to
+            // CLEANUP_TIMEOUT_MILLIS - in which case it's probably best to just cancel that effect
+            // explicitly at the end of the test case (rather than letting it run and race flakily).
+            assertTrue(waitUntil(s -> {
+                for (int vibratorId : mService.getVibratorIds()) {
+                    if (s.isVibrating(vibratorId)) {
+                        return false;
+                    }
+                }
+                return true;
+            }, mService, CLEANUP_TIMEOUT_MILLIS));
+        }
+
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
+        // Ignore potential exceptions about the looper having never dispatched any messages.
+        mTestLooper.stopAutoDispatchAndIgnoreExceptions();
     }
 
     private VibratorManagerService createSystemReadyService() {
@@ -240,7 +264,7 @@
     }
 
     private VibratorManagerService createService() {
-        return new VibratorManagerService(
+        mService = new VibratorManagerService(
                 mContextSpy,
                 new VibratorManagerService.Injector() {
                     @Override
@@ -277,6 +301,7 @@
                                 (VibratorManagerService.ExternalVibratorService) serviceInstance;
                     }
                 });
+        return mService;
     }
 
     @Test
@@ -477,6 +502,7 @@
         verify(listeners[0]).onVibrating(eq(true));
         verify(listeners[1]).onVibrating(eq(true));
         verify(listeners[2], never()).onVibrating(eq(true));
+        cancelVibrate(service);
     }
 
     @Test
@@ -803,6 +829,7 @@
         assertFalse(
                 mVibratorProviders.get(1).getAllEffectSegments().stream()
                         .anyMatch(segment -> segment instanceof PrebakedSegment));
+        cancelVibrate(service);  // Clean up repeating effect.
     }
 
     @Test
@@ -829,6 +856,8 @@
 
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
+
+        cancelVibrate(service);  // Clean up repeating effect.
     }
 
     @Test
@@ -854,6 +883,8 @@
         assertFalse(
                 mVibratorProviders.get(1).getAllEffectSegments().stream()
                         .anyMatch(segment -> segment instanceof PrebakedSegment));
+
+        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
@@ -885,6 +916,40 @@
     }
 
     @Test
+    public void vibrate_withOngoingSameImportancePipelinedVibration_continuesOngoingEffect()
+            throws Exception {
+        VibrationAttributes pipelineAttrs = new VibrationAttributes.Builder(HAPTIC_FEEDBACK_ATTRS)
+                .setFlags(VibrationAttributes.FLAG_PIPELINED_EFFECT)
+                .build();
+
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        VibratorManagerService service = createSystemReadyService();
+
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                new long[]{100, 100}, new int[]{128, 255}, -1);
+        vibrate(service, effect, pipelineAttrs);
+        // This vibration will be enqueued, but evicted by the EFFECT_CLICK.
+        vibrate(service, VibrationEffect.startComposition()
+                .addOffDuration(Duration.ofSeconds(10))
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_SLOW_RISE)
+                .compose(), pipelineAttrs);  // This will queue and be evicted for the click.
+
+        vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
+                pipelineAttrs);
+
+        // The second vibration should have recorded that the vibrators were turned on.
+        verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
+        // One step segment (with several amplitudes) and one click should have played. Notably
+        // there is no primitive segment.
+        List<VibrationEffectSegment> played = mVibratorProviders.get(1).getAllEffectSegments();
+        assertEquals(2, played.size());
+        assertEquals(1, played.stream().filter(StepSegment.class::isInstance).count());
+        assertEquals(1, played.stream().filter(PrebakedSegment.class::isInstance).count());
+    }
+
+    @Test
     public void vibrate_withInputDevices_vibratesInputDevices() throws Exception {
         mockVibrators(1);
         mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
@@ -1159,10 +1224,11 @@
 
         // Vibration is not stopped nearly after updating service.
         assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50));
+        cancelVibrate(service);
     }
 
     @Test
-    public void vibrate_withVitualDisplayChange_ignoreVibrationFromVirtualDisplay()
+    public void vibrate_withVirtualDisplayChange_ignoreVibrationFromVirtualDisplay()
             throws Exception {
         mockVibrators(1);
         VibratorManagerService service = createSystemReadyService();
@@ -1188,10 +1254,11 @@
         // Haptic feedback played normally when the virtual display is removed.
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
 
+        cancelVibrate(service);  // Clean up long-ish effect.
     }
 
     @Test
-    public void vibrate_withAppsOnVitualDisplayChange_ignoreVibrationFromVirtualDisplay()
+    public void vibrate_withAppsOnVirtualDisplayChange_ignoreVibrationFromVirtualDisplay()
             throws Exception {
         mockVibrators(1);
         VibratorManagerService service = createSystemReadyService();
@@ -1216,7 +1283,7 @@
                 HAPTIC_FEEDBACK_ATTRS);
         // Haptic feedback played normally when the same app no long runs on a virtual display.
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
-
+        cancelVibrate(service);  // Clean up long-ish effect.
     }
 
     @Test
@@ -1900,6 +1967,10 @@
         when(mNativeWrapperMock.getVibratorIds()).thenReturn(vibratorIds);
     }
 
+    private void cancelVibrate(VibratorManagerService service) {
+        service.cancelVibrate(VibrationAttributes.USAGE_FILTER_MATCH_ALL, service);
+    }
+
     private IVibratorStateListener mockVibratorStateListener() {
         IVibratorStateListener listenerMock = mock(IVibratorStateListener.class);
         IBinder binderMock = mock(IBinder.class);
@@ -1908,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/Android.bp b/services/tests/uiservicestests/Android.bp
index 75e2892..94f2d2e 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -20,6 +20,7 @@
     ],
 
     static_libs: [
+        "frameworks-base-testutils",
         "services.accessibility",
         "services.core",
         "services.devicepolicy",
@@ -33,6 +34,7 @@
         "platformprotosnano",
         "statsdprotolite",
         "hamcrest-library",
+        "servicestests-utils",
         "testables",
         "truth-prebuilt",
         // TODO: remove once Android migrates to JUnit 4.12,
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index aee2755..617a34f 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -45,6 +45,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.notNull;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.BDDMockito.given;
 import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.atLeastOnce;
@@ -58,31 +59,36 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
-import static org.mockito.MockitoAnnotations.initMocks;
 import static org.testng.Assert.assertThrows;
 
 import android.Manifest;
+import android.app.Activity;
 import android.app.AlarmManager;
 import android.app.IOnProjectionStateChangedListener;
 import android.app.IUiModeManager;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.Process;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.dreams.DreamManagerInternal;
+import android.test.mock.MockContentResolver;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
@@ -93,6 +99,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 
 import java.time.LocalDateTime;
@@ -107,8 +114,7 @@
     private static final String PACKAGE_NAME = "Diane Coffee";
     private UiModeManagerService mUiManagerService;
     private IUiModeManager mService;
-    @Mock
-    private ContentResolver mContentResolver;
+    private MockContentResolver mContentResolver;
     @Mock
     private WindowManagerInternal mWindowManager;
     @Mock
@@ -131,16 +137,22 @@
     private PackageManager mPackageManager;
     @Mock
     private IBinder mBinder;
+    @Mock
+    private DreamManagerInternal mDreamManager;
+    @Captor
+    private ArgumentCaptor<Intent> mOrderedBroadcastIntent;
+    @Captor
+    private ArgumentCaptor<BroadcastReceiver> mOrderedBroadcastReceiver;
 
     private BroadcastReceiver mScreenOffCallback;
     private BroadcastReceiver mTimeChangedCallback;
+    private BroadcastReceiver mDockStateChangedCallback;
     private AlarmManager.OnAlarmListener mCustomListener;
     private Consumer<PowerSaveState> mPowerSaveConsumer;
     private TwilightListener mTwilightListener;
 
     @Before
     public void setUp() {
-        initMocks(this);
         when(mContext.checkCallingOrSelfPermission(anyString()))
                 .thenReturn(PackageManager.PERMISSION_GRANTED);
         doAnswer(inv -> {
@@ -154,6 +166,10 @@
         when(mLocalPowerManager.getLowPowerState(anyInt()))
                 .thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(false).build());
         when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getString(com.android.internal.R.string.config_somnambulatorComponent))
+                .thenReturn("somnambulator");
+        mContentResolver = new MockContentResolver();
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPowerManager.isInteractive()).thenReturn(true);
@@ -168,6 +184,9 @@
             if (filter.hasAction(Intent.ACTION_SCREEN_OFF)) {
                 mScreenOffCallback = inv.getArgument(0);
             }
+            if (filter.hasAction(Intent.ACTION_DOCK_EVENT)) {
+                mDockStateChangedCallback = inv.getArgument(0);
+            }
             return null;
         });
         doAnswer(inv -> {
@@ -182,11 +201,13 @@
         }).when(mAlarmManager).cancel(eq(mCustomListener));
         when(mContext.getSystemService(eq(Context.POWER_SERVICE)))
                 .thenReturn(mPowerManager);
+        when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
         when(mContext.getSystemService(eq(Context.ALARM_SERVICE)))
                 .thenReturn(mAlarmManager);
         addLocalService(WindowManagerInternal.class, mWindowManager);
         addLocalService(PowerManagerInternal.class, mLocalPowerManager);
         addLocalService(TwilightManager.class, mTwilightManager);
+        addLocalService(DreamManagerInternal.class, mDreamManager);
         
         mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
                 mTwilightManager, new TestInjector());
@@ -1298,6 +1319,138 @@
         assertThat(mService.getCurrentModeType()).isNotEqualTo(Configuration.UI_MODE_TYPE_CAR);
     }
 
+    @Test
+    public void dreamWhenDocked() {
+        setScreensaverActivateOnDock(true);
+        setScreensaverEnabled(true);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager).requestDream();
+    }
+
+    @Test
+    public void noDreamWhenDocked_dreamsDisabled() {
+        setScreensaverActivateOnDock(true);
+        setScreensaverEnabled(false);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager, never()).requestDream();
+    }
+
+    @Test
+    public void noDreamWhenDocked_dreamsWhenDockedDisabled() {
+        setScreensaverActivateOnDock(false);
+        setScreensaverEnabled(true);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager, never()).requestDream();
+    }
+
+    @Test
+    public void noDreamWhenDocked_keyguardNotShowing_interactive() {
+        setScreensaverActivateOnDock(true);
+        setScreensaverEnabled(true);
+        mUiManagerService.setStartDreamImmediatelyOnDock(false);
+        when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(false);
+        when(mPowerManager.isInteractive()).thenReturn(true);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager, never()).requestDream();
+    }
+
+    @Test
+    public void dreamWhenDocked_keyguardShowing_interactive() {
+        setScreensaverActivateOnDock(true);
+        setScreensaverEnabled(true);
+        mUiManagerService.setStartDreamImmediatelyOnDock(false);
+        when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(true);
+        when(mPowerManager.isInteractive()).thenReturn(false);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager).requestDream();
+    }
+
+    @Test
+    public void dreamWhenDocked_keyguardNotShowing_notInteractive() {
+        setScreensaverActivateOnDock(true);
+        setScreensaverEnabled(true);
+        mUiManagerService.setStartDreamImmediatelyOnDock(false);
+        when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(false);
+        when(mPowerManager.isInteractive()).thenReturn(false);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager).requestDream();
+    }
+
+    @Test
+    public void dreamWhenDocked_keyguardShowing_notInteractive() {
+        setScreensaverActivateOnDock(true);
+        setScreensaverEnabled(true);
+        mUiManagerService.setStartDreamImmediatelyOnDock(false);
+        when(mWindowManager.isKeyguardShowingAndNotOccluded()).thenReturn(true);
+        when(mPowerManager.isInteractive()).thenReturn(false);
+
+        triggerDockIntent();
+        verifyAndSendResultBroadcast();
+        verify(mDreamManager).requestDream();
+    }
+
+    private void triggerDockIntent() {
+        final Intent dockedIntent =
+                new Intent(Intent.ACTION_DOCK_EVENT)
+                        .putExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_DESK);
+        mDockStateChangedCallback.onReceive(mContext, dockedIntent);
+    }
+
+    private void verifyAndSendResultBroadcast() {
+        verify(mContext).sendOrderedBroadcastAsUser(
+                mOrderedBroadcastIntent.capture(),
+                any(UserHandle.class),
+                nullable(String.class),
+                mOrderedBroadcastReceiver.capture(),
+                nullable(Handler.class),
+                anyInt(),
+                nullable(String.class),
+                nullable(Bundle.class));
+
+        mOrderedBroadcastReceiver.getValue().setPendingResult(
+                new BroadcastReceiver.PendingResult(
+                        Activity.RESULT_OK,
+                        /* resultData= */ "",
+                        /* resultExtras= */ null,
+                        /* type= */ 0,
+                        /* ordered= */ true,
+                        /* sticky= */ false,
+                        /* token= */ null,
+                        /* userId= */ 0,
+                        /* flags= */ 0));
+        mOrderedBroadcastReceiver.getValue().onReceive(
+                mContext,
+                mOrderedBroadcastIntent.getValue());
+    }
+
+    private void setScreensaverEnabled(boolean enable) {
+        Settings.Secure.putIntForUser(
+                mContentResolver,
+                Settings.Secure.SCREENSAVER_ENABLED,
+                enable ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
+    private void setScreensaverActivateOnDock(boolean enable) {
+        Settings.Secure.putIntForUser(
+                mContentResolver,
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+                enable ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
     private void requestAllPossibleProjectionTypes() throws RemoteException {
         for (int i = 0; i < Integer.SIZE; ++i) {
             mService.requestProjection(mBinder, 1 << i, PACKAGE_NAME);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 8ba9af0..49879efe 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -15,6 +15,11 @@
  */
 package com.android.server.notification;
 
+import static android.content.Context.DEVICE_POLICY_SERVICE;
+import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
+import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
+import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+
 import static com.android.server.notification.ManagedServices.APPROVAL_BY_COMPONENT;
 import static com.android.server.notification.ManagedServices.APPROVAL_BY_PACKAGE;
 
@@ -34,6 +39,8 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.ActivityManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -94,6 +101,7 @@
     private UserManager mUm;
     @Mock
     private ManagedServices.UserProfiles mUserProfiles;
+    @Mock private DevicePolicyManager mDpm;
     Object mLock = new Object();
 
     UserInfo mZero = new UserInfo(0, "zero", 0);
@@ -122,6 +130,7 @@
 
         getContext().setMockPackageManager(mPm);
         getContext().addMockSystemService(Context.USER_SERVICE, mUm);
+        getContext().addMockSystemService(DEVICE_POLICY_SERVICE, mDpm);
 
         List<UserInfo> users = new ArrayList<>();
         users.add(mZero);
@@ -1694,6 +1703,58 @@
         assertEquals(new ArrayMap(), mService.mIsUserChanged);
     }
 
+    @Test
+    public void testInfoIsPermittedForProfile_notAllowed() {
+        when(mUserProfiles.canProfileUseBoundServices(anyInt())).thenReturn(false);
+
+        IInterface service = mock(IInterface.class);
+        when(service.asBinder()).thenReturn(mock(IBinder.class));
+        ManagedServices services = new TestManagedServices(getContext(), mLock, mUserProfiles,
+                mIpm, APPROVAL_BY_PACKAGE);
+        services.registerSystemService(service, null, 10, 1000);
+        ManagedServices.ManagedServiceInfo info = services.checkServiceTokenLocked(service);
+
+        assertFalse(info.isPermittedForProfile(0));
+    }
+
+    @Test
+    public void testInfoIsPermittedForProfile_allows() {
+        when(mUserProfiles.canProfileUseBoundServices(anyInt())).thenReturn(true);
+        when(mDpm.isNotificationListenerServicePermitted(anyString(), anyInt())).thenReturn(true);
+
+        IInterface service = mock(IInterface.class);
+        when(service.asBinder()).thenReturn(mock(IBinder.class));
+        ManagedServices services = new TestManagedServices(getContext(), mLock, mUserProfiles,
+                mIpm, APPROVAL_BY_PACKAGE);
+        services.registerSystemService(service, null, 10, 1000);
+        ManagedServices.ManagedServiceInfo info = services.checkServiceTokenLocked(service);
+        info.component = new ComponentName("a","b");
+
+        assertTrue(info.isPermittedForProfile(0));
+    }
+
+    @Test
+    public void testUserProfiles_canProfileUseBoundServices_managedProfile() {
+        List<UserInfo> users = new ArrayList<>();
+        UserInfo profile = new UserInfo(ActivityManager.getCurrentUser(), "current", 0);
+        profile.userType = USER_TYPE_FULL_SECONDARY;
+        users.add(profile);
+        UserInfo managed = new UserInfo(12, "12", 0);
+        managed.userType = USER_TYPE_PROFILE_MANAGED;
+        users.add(managed);
+        UserInfo clone = new UserInfo(13, "13", 0);
+        clone.userType = USER_TYPE_PROFILE_CLONE;
+        users.add(clone);
+        when(mUm.getProfiles(ActivityManager.getCurrentUser())).thenReturn(users);
+
+        ManagedServices.UserProfiles profiles = new ManagedServices.UserProfiles();
+        profiles.updateCache(mContext);
+
+        assertTrue(profiles.canProfileUseBoundServices(ActivityManager.getCurrentUser()));
+        assertFalse(profiles.canProfileUseBoundServices(12));
+        assertFalse(profiles.canProfileUseBoundServices(13));
+    }
+
     private void resetComponentsAndPackages() {
         ArrayMap<Integer, ArrayMap<Integer, String>> empty = new ArrayMap(1);
         ArrayMap<Integer, String> emptyPkgs = new ArrayMap(0);
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 ec48e23..cae8fd9 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -58,6 +58,9 @@
 import static android.os.Build.VERSION_CODES.O_MR1;
 import static android.os.Build.VERSION_CODES.P;
 import static android.os.UserHandle.USER_SYSTEM;
+import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
+import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
+import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
 import static android.service.notification.Adjustment.KEY_IMPORTANCE;
 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING;
@@ -212,6 +215,7 @@
 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
 import com.android.server.notification.NotificationManagerService.NotificationListeners;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.UserManagerInternal;
 import com.android.server.policy.PermissionPolicyInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -353,6 +357,8 @@
     @Mock
     UserManager mUm;
     @Mock
+    UserManagerInternal mUmInternal;
+    @Mock
     NotificationHistoryManager mHistoryManager;
     @Mock
     StatsManager mStatsManager;
@@ -394,6 +400,8 @@
         DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
         when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
 
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+        LocalServices.addService(UserManagerInternal.class, mUmInternal);
         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
         LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
@@ -4464,6 +4472,33 @@
     }
 
     @Test
+    public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception {
+        final String policyXml = "<notification-policy version=\"1\">"
+                + "<ranking></ranking>"
+                + "<enabled_listeners>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</enabled_listeners>"
+                + "<enabled_assistants>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</enabled_assistants>"
+                + "<dnd_apps>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</dnd_apps>"
+                + "</notification-policy>";
+        UserInfo ui = new UserInfo();
+        ui.id = 10;
+        ui.userType = USER_TYPE_PROFILE_CLONE;
+        when(mUmInternal.getUserInfo(10)).thenReturn(ui);
+        mService.readPolicyXml(
+                new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
+                true,
+                10);
+        verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
+        verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
+        verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
+    }
+
+    @Test
     public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception {
         final String policyXml = "<notification-policy version=\"1\">"
                 + "<ranking></ranking>"
@@ -4477,7 +4512,10 @@
                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
                 + "</dnd_apps>"
                 + "</notification-policy>";
-        when(mUm.isManagedProfile(10)).thenReturn(true);
+        UserInfo ui = new UserInfo();
+        ui.id = 10;
+        ui.userType = USER_TYPE_PROFILE_MANAGED;
+        when(mUmInternal.getUserInfo(10)).thenReturn(ui);
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
@@ -4501,7 +4539,10 @@
                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
                 + "</dnd_apps>"
                 + "</notification-policy>";
-        when(mUm.isManagedProfile(10)).thenReturn(false);
+        UserInfo ui = new UserInfo();
+        ui.id = 10;
+        ui.userType = USER_TYPE_FULL_SECONDARY;
+        when(mUmInternal.getUserInfo(10)).thenReturn(ui);
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
@@ -6158,6 +6199,62 @@
     }
 
     @Test
+    public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() {
+        for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
+            Notification n = new Notification.Builder(mContext, "").build();
+            StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0,
+                    n, UserHandle.getUserHandleForUid(mUid), null, 0);
+            NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+            mService.addEnqueuedNotification(r);
+        }
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG,
+                NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addEnqueuedNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.getSbn().getId(), r.getSbn().getUserId());
+
+        waitForIdle();
+
+        assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
+                mService.getNotificationRecordCount());
+    }
+
+    @Test
+    public void testCannotRemoveForegroundFlagWhenOverLimit_posted() {
+        for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) {
+            Notification n = new Notification.Builder(mContext, "").build();
+            StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, i, null, mUid, 0,
+                    n, UserHandle.getUserHandleForUid(mUid), null, 0);
+            NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+            mService.addNotification(r);
+        }
+        Notification n = new Notification.Builder(mContext, "").build();
+        n.flags |= FLAG_FOREGROUND_SERVICE;
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG,
+                NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0,
+                n, UserHandle.getUserHandleForUid(mUid), null, 0);
+        NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mService.addNotification(r);
+
+        mInternalService.removeForegroundServiceFlagFromNotification(
+                PKG, r.getSbn().getId(), r.getSbn().getUserId());
+
+        waitForIdle();
+
+        assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS,
+                mService.getNotificationRecordCount());
+    }
+
+    @Test
     public void testAllowForegroundCustomToasts() throws Exception {
         final String testPackage = "testPackageName";
         assertEquals(0, mService.mToastQueue.size());
@@ -7507,6 +7604,43 @@
     }
 
     @Test
+    public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception {
+        mService.isSystemUid = true;
+        ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+        when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+                .thenReturn(true);
+        mService.setZenHelper(mockZenModeHelper);
+        ComponentName owner = new ComponentName("android", "ProviderName");
+        ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+        boolean isEnabled = true;
+        AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+        mBinderService.addAutomaticZenRule(rule, "com.android.settings");
+
+        // verify that zen mode helper gets passed in a package name of "android"
+        verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString());
+    }
+
+    @Test
+    public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception {
+        mService.isSystemUid = false;
+        ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class);
+        when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt()))
+                .thenReturn(true);
+        mService.setZenHelper(mockZenModeHelper);
+        ComponentName owner = new ComponentName("android", "ProviderName");
+        ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+        boolean isEnabled = true;
+        AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+        mBinderService.addAutomaticZenRule(rule, "another.package");
+
+        // verify that zen mode helper gets passed in the package name from the arg, not the owner
+        verify(mockZenModeHelper).addAutomaticZenRule(
+                eq("another.package"), eq(rule), anyString());
+    }
+
+    @Test
     public void testAreNotificationsEnabledForPackage() throws Exception {
         mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
                 mUid);
diff --git a/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java b/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java
new file mode 100644
index 0000000..62875e5
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/CombinationKeyTests.java
@@ -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.server.policy;
+
+import static android.view.KeyEvent.KEYCODE_POWER;
+import static android.view.KeyEvent.KEYCODE_VOLUME_DOWN;
+import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
+
+import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS;
+import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE;
+
+import android.view.ViewConfiguration;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for combination key shortcuts.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:CombinationKeyTests
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CombinationKeyTests extends ShortcutKeyTestBase {
+    private static final long A11Y_KEY_HOLD_MILLIS = 3500;
+
+    /**
+     * Power-VolDown to take screenshot.
+     */
+    @Test
+    public void testPowerVolumeDown() {
+        sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_DOWN},
+                ViewConfiguration.get(mContext).getScreenshotChordKeyTimeout());
+        mPhoneWindowManager.assertTakeScreenshotCalled();
+    }
+
+    /**
+     * Power-VolUp to show global actions or mute audio. (Phone default behavior)
+     */
+    @Test
+    public void testPowerVolumeUp() {
+        // Show global actions.
+        mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_GLOBAL_ACTIONS);
+        sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 0);
+        mPhoneWindowManager.assertShowGlobalActionsCalled();
+
+        // Mute audio (hold over 100ms).
+        mPhoneWindowManager.overridePowerVolumeUp(POWER_VOLUME_UP_BEHAVIOR_MUTE);
+        sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 100);
+        mPhoneWindowManager.assertVolumeMute();
+    }
+
+    /**
+     * VolDown-VolUp and hold 3 secs to enable accessibility service.
+     */
+    @Test
+    public void testVolumeDownVolumeUp() {
+        sendKeyCombination(new int[]{KEYCODE_VOLUME_DOWN, KEYCODE_VOLUME_UP}, A11Y_KEY_HOLD_MILLIS);
+        mPhoneWindowManager.assertAccessibilityKeychordCalled();
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyCombinationManagerTests.java
similarity index 88%
rename from services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
rename to services/tests/wmtests/src/com/android/server/policy/KeyCombinationManagerTests.java
index cf57181..487390d 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyCombinationTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyCombinationManagerTests.java
@@ -43,11 +43,11 @@
  * Test class for {@link KeyCombinationManager}.
  *
  * Build/Install/Run:
- *  atest KeyCombinationTests
+ *  atest KeyCombinationManagerTests
  */
 
 @SmallTest
-public class KeyCombinationTests {
+public class KeyCombinationManagerTests {
     private KeyCombinationManager mKeyCombinationManager;
 
     private final CountDownLatch mAction1Triggered = new CountDownLatch(1);
@@ -228,4 +228,30 @@
         mKeyCombinationManager.interceptKey(firstKeyDown, true);
         assertTrue(mKeyCombinationManager.getKeyInterceptTimeout(KEYCODE_VOLUME_UP) > eventTime);
     }
+
+    @Test
+    public void testAddRemove() throws InterruptedException {
+        final KeyCombinationManager.TwoKeysCombinationRule rule =
+                new KeyCombinationManager.TwoKeysCombinationRule(KEYCODE_VOLUME_DOWN,
+                        KEYCODE_POWER) {
+                    @Override
+                    void execute() {
+                        mAction1Triggered.countDown();
+                    }
+
+                    @Override
+                    void cancel() {
+                    }
+                };
+
+        long eventTime = SystemClock.uptimeMillis();
+        mKeyCombinationManager.removeRule(rule);
+        pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_DOWN);
+        assertFalse(mAction1Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
+
+        mKeyCombinationManager.addRule(rule);
+        eventTime = SystemClock.uptimeMillis();
+        pressKeys(eventTime, KEYCODE_POWER, eventTime, KEYCODE_VOLUME_DOWN);
+        assertTrue(mAction1Triggered.await(SCHEDULE_TIME, TimeUnit.MILLISECONDS));
+    }
 }
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
new file mode 100644
index 0000000..49af2c1
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/PowerKeyGestureTests.java
@@ -0,0 +1,98 @@
+/*
+ * 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.policy;
+
+import static android.view.KeyEvent.KEYCODE_POWER;
+import static android.view.KeyEvent.KEYCODE_VOLUME_UP;
+
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS;
+
+import android.provider.Settings;
+import android.view.Display;
+
+import org.junit.Test;
+
+/**
+ * Test class for power key gesture.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:PowerKeyGestureTests
+ */
+public class PowerKeyGestureTests extends ShortcutKeyTestBase {
+    /**
+     * Power single press to turn screen on/off.
+     */
+    @Test
+    public void testPowerSinglePress() {
+        sendKey(KEYCODE_POWER);
+        mPhoneWindowManager.assertPowerSleep();
+
+        // turn screen on when begin from non-interactive.
+        mPhoneWindowManager.overrideDisplayState(Display.STATE_OFF);
+        sendKey(KEYCODE_POWER);
+        mPhoneWindowManager.assertPowerWakeUp();
+        mPhoneWindowManager.assertNoPowerSleep();
+    }
+
+    /**
+     * Power double press to trigger camera.
+     */
+    @Test
+    public void testPowerDoublePress() {
+        sendKey(KEYCODE_POWER);
+        sendKey(KEYCODE_POWER);
+        mPhoneWindowManager.assertCameraLaunch();
+    }
+
+    /**
+     * Power long press to show assistant or global actions.
+     */
+    @Test
+    public void testPowerLongPress() {
+        // Show assistant.
+        mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_ASSISTANT);
+        sendKey(KEYCODE_POWER, true);
+        mPhoneWindowManager.assertAssistLaunch();
+
+        // Show global actions.
+        mPhoneWindowManager.overrideLongPressOnPower(LONG_PRESS_POWER_GLOBAL_ACTIONS);
+        sendKey(KEYCODE_POWER, true);
+        mPhoneWindowManager.assertShowGlobalActionsCalled();
+    }
+
+    /**
+     * Ignore power press if combination key already triggered.
+     */
+    @Test
+    public void testIgnoreSinglePressWhenCombinationKeyTriggered() {
+        sendKeyCombination(new int[]{KEYCODE_POWER, KEYCODE_VOLUME_UP}, 0);
+        mPhoneWindowManager.assertNoPowerSleep();
+    }
+
+    /**
+     * When a phone call is active, and INCALL_POWER_BUTTON_BEHAVIOR_HANGUP is enabled, then the
+     * power button should only stop phone call. The screen should not be turned off (power sleep
+     * should not be activated).
+     */
+    @Test
+    public void testIgnoreSinglePressWhenEndCall() {
+        mPhoneWindowManager.overrideIncallPowerBehavior(
+                Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP);
+        sendKey(KEYCODE_POWER);
+        mPhoneWindowManager.assertNoPowerSleep();
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
new file mode 100644
index 0000000..6368f47
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -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.server.policy;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.KeyEvent.KEYCODE_ALT_LEFT;
+import static android.view.KeyEvent.KEYCODE_ALT_RIGHT;
+import static android.view.KeyEvent.KEYCODE_CTRL_LEFT;
+import static android.view.KeyEvent.KEYCODE_CTRL_RIGHT;
+import static android.view.KeyEvent.KEYCODE_META_LEFT;
+import static android.view.KeyEvent.KEYCODE_META_RIGHT;
+import static android.view.KeyEvent.KEYCODE_SHIFT_LEFT;
+import static android.view.KeyEvent.KEYCODE_SHIFT_RIGHT;
+import static android.view.KeyEvent.META_ALT_LEFT_ON;
+import static android.view.KeyEvent.META_ALT_ON;
+import static android.view.KeyEvent.META_ALT_RIGHT_ON;
+import static android.view.KeyEvent.META_CTRL_LEFT_ON;
+import static android.view.KeyEvent.META_CTRL_ON;
+import static android.view.KeyEvent.META_CTRL_RIGHT_ON;
+import static android.view.KeyEvent.META_META_LEFT_ON;
+import static android.view.KeyEvent.META_META_ON;
+import static android.view.KeyEvent.META_META_RIGHT_ON;
+import static android.view.KeyEvent.META_SHIFT_LEFT_ON;
+import static android.view.KeyEvent.META_SHIFT_ON;
+import static android.view.KeyEvent.META_SHIFT_RIGHT_ON;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.server.policy.WindowManagerPolicy.ACTION_PASS_TO_USER;
+
+import static java.util.Collections.unmodifiableMap;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.util.Map;
+
+class ShortcutKeyTestBase {
+    TestPhoneWindowManager mPhoneWindowManager;
+    final Context mContext = getInstrumentation().getTargetContext();
+
+    /** Modifier key to meta state */
+    private static final Map<Integer, Integer> MODIFIER;
+    static {
+        final Map<Integer, Integer> map = new ArrayMap<>();
+        map.put(KEYCODE_CTRL_LEFT, META_CTRL_LEFT_ON | META_CTRL_ON);
+        map.put(KEYCODE_CTRL_RIGHT, META_CTRL_RIGHT_ON | META_CTRL_ON);
+        map.put(KEYCODE_ALT_LEFT, META_ALT_LEFT_ON | META_ALT_ON);
+        map.put(KEYCODE_ALT_RIGHT, META_ALT_RIGHT_ON | META_ALT_ON);
+        map.put(KEYCODE_SHIFT_LEFT, META_SHIFT_LEFT_ON | META_SHIFT_ON);
+        map.put(KEYCODE_SHIFT_RIGHT, META_SHIFT_RIGHT_ON | META_SHIFT_ON);
+        map.put(KEYCODE_META_LEFT, META_META_LEFT_ON | META_META_ON);
+        map.put(KEYCODE_META_RIGHT, META_META_RIGHT_ON | META_META_ON);
+
+        MODIFIER = unmodifiableMap(map);
+    }
+
+    @Before
+    public void setUp() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+
+        mPhoneWindowManager = new TestPhoneWindowManager(mContext);
+    }
+
+    @After
+    public void tearDown() {
+        mPhoneWindowManager.tearDown();
+    }
+
+    void sendKeyCombination(int[] keyCodes, long duration) {
+        final long downTime = SystemClock.uptimeMillis();
+        final int count = keyCodes.length;
+        final KeyEvent[] events = new KeyEvent[count];
+        int metaState = 0;
+        for (int i = 0; i < count; i++) {
+            final int keyCode = keyCodes[i];
+            final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
+                    0 /*repeat*/, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+                    0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
+            event.setDisplayId(DEFAULT_DISPLAY);
+            events[i] = event;
+            // The order is important here, metaState could be updated and applied to the next key.
+            metaState |= MODIFIER.getOrDefault(keyCode, 0);
+        }
+
+        for (KeyEvent event: events) {
+            interceptKey(event);
+        }
+
+        try {
+            Thread.sleep(duration);
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+
+        for (KeyEvent event: events) {
+            final long eventTime = SystemClock.uptimeMillis();
+            final int keyCode = event.getKeyCode();
+            final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
+                    0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
+                    InputDevice.SOURCE_KEYBOARD);
+            interceptKey(upEvent);
+            metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
+        }
+    }
+
+    void sendKey(int keyCode) {
+        sendKey(keyCode, false);
+    }
+
+    void sendKey(int keyCode, boolean longPress) {
+        final long downTime = SystemClock.uptimeMillis();
+        final KeyEvent event = new KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode,
+                0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+                0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
+        event.setDisplayId(DEFAULT_DISPLAY);
+        interceptKey(event);
+
+        if (longPress) {
+            final long nextDownTime = downTime + ViewConfiguration.getLongPressTimeout();
+            final KeyEvent nextDownevent = new KeyEvent(downTime, nextDownTime,
+                    KeyEvent.ACTION_DOWN, keyCode, 1 /*repeat*/, 0 /*metaState*/,
+                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+                    KeyEvent.FLAG_LONG_PRESS /*flags*/, InputDevice.SOURCE_KEYBOARD);
+            interceptKey(nextDownevent);
+        }
+
+        final long eventTime = longPress
+                ? SystemClock.uptimeMillis() + ViewConfiguration.getLongPressTimeout()
+                : SystemClock.uptimeMillis();
+        final KeyEvent upEvent = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP, keyCode,
+                0 /*repeat*/, 0 /*metaState*/, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/,
+                0 /*flags*/, InputDevice.SOURCE_KEYBOARD);
+        interceptKey(upEvent);
+    }
+
+    private void interceptKey(KeyEvent keyEvent) {
+        int actions = mPhoneWindowManager.interceptKeyBeforeQueueing(keyEvent);
+        if ((actions & ACTION_PASS_TO_USER) != 0) {
+            if (0 == mPhoneWindowManager.interceptKeyBeforeDispatching(keyEvent)) {
+                mPhoneWindowManager.dispatchUnhandledKey(keyEvent);
+            }
+        }
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
index 8f94468..280afba 100644
--- a/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/SingleKeyGestureTests.java
@@ -297,4 +297,23 @@
         pressKey(KEYCODE_BACK, mLongPressTime);
         assertTrue(mLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
     }
+
+    @Test
+    public void testAddRemove() throws InterruptedException {
+        final SingleKeyGestureDetector.SingleKeyRule rule =
+                new SingleKeyGestureDetector.SingleKeyRule(KEYCODE_POWER) {
+                    @Override
+                    void onPress(long downTime) {
+                        mShortPressed.countDown();
+                    }
+                };
+
+        mDetector.removeRule(rule);
+        pressKey(KEYCODE_POWER, 0 /* pressTime */);
+        assertFalse(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+
+        mDetector.addRule(rule);
+        pressKey(KEYCODE_POWER, 0 /* pressTime */);
+        assertTrue(mShortPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
new file mode 100644
index 0000000..ee11ac8
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -0,0 +1,371 @@
+/*
+ * 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.policy;
+
+import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.STATE_ON;
+import static android.view.WindowManagerPolicyConstants.FLAG_INTERACTIVE;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GO_TO_VOICE_ASSIST;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_NOTHING;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_SHUT_OFF;
+import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
+import static com.android.server.policy.PhoneWindowManager.POWER_VOLUME_UP_BEHAVIOR_MUTE;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.CALLS_REAL_METHODS;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.withSettings;
+
+import android.app.ActivityManagerInternal;
+import android.app.AppOpsManager;
+import android.app.NotificationManager;
+import android.app.SearchManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManagerInternal;
+import android.hardware.input.InputManagerInternal;
+import android.media.AudioManagerInternal;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.Vibrator;
+import android.service.dreams.DreamManagerInternal;
+import android.telecom.TelecomManager;
+import android.view.Display;
+import android.view.KeyEvent;
+import android.view.autofill.AutofillManagerInternal;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.server.GestureLauncherService;
+import com.android.server.LocalServices;
+import com.android.server.vr.VrManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.DisplayPolicy;
+import com.android.server.wm.DisplayRotation;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.mockito.Mock;
+import org.mockito.MockSettings;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Supplier;
+
+class TestPhoneWindowManager {
+    private static final long SHORTCUT_KEY_DELAY_MILLIS = 150;
+
+    private PhoneWindowManager mPhoneWindowManager;
+    private Context mContext;
+
+    @Mock private WindowManagerInternal mWindowManagerInternal;
+    @Mock private ActivityManagerInternal mActivityManagerInternal;
+    @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+    @Mock private InputManagerInternal mInputManagerInternal;
+    @Mock private DreamManagerInternal mDreamManagerInternal;
+    @Mock private PowerManagerInternal mPowerManagerInternal;
+    @Mock private DisplayManagerInternal mDisplayManagerInternal;
+    @Mock private AppOpsManager mAppOpsManager;
+    @Mock private DisplayManager mDisplayManager;
+    @Mock private PackageManager mPackageManager;
+    @Mock private TelecomManager mTelecomManager;
+    @Mock private NotificationManager mNotificationManager;
+    @Mock private Vibrator mVibrator;
+    @Mock private PowerManager mPowerManager;
+    @Mock private WindowManagerPolicy.WindowManagerFuncs mWindowManagerFuncsImpl;
+    @Mock private AudioManagerInternal mAudioManagerInternal;
+    @Mock private SearchManager mSearchManager;
+
+    @Mock private Display mDisplay;
+    @Mock private DisplayRotation mDisplayRotation;
+    @Mock private DisplayPolicy mDisplayPolicy;
+    @Mock private WindowManagerPolicy.ScreenOnListener mScreenOnListener;
+    @Mock private GestureLauncherService mGestureLauncherService;
+    @Mock private GlobalActions mGlobalActions;
+    @Mock private AccessibilityShortcutController mAccessibilityShortcutController;
+
+    private StaticMockitoSession mMockitoSession;
+    private HandlerThread mHandlerThread;
+    private Handler mHandler;
+
+    private class TestInjector extends PhoneWindowManager.Injector {
+        TestInjector(Context context, WindowManagerPolicy.WindowManagerFuncs funcs) {
+            super(context, funcs);
+        }
+
+        AccessibilityShortcutController getAccessibilityShortcutController(
+                Context context, Handler handler, int initialUserId) {
+            return mAccessibilityShortcutController;
+        }
+
+        Supplier<GlobalActions> getGlobalActionsFactory() {
+            return () -> mGlobalActions;
+        }
+    }
+
+    TestPhoneWindowManager(Context context) {
+        MockitoAnnotations.initMocks(this);
+        mHandlerThread = new HandlerThread("fake window manager");
+        mHandlerThread.start();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        mHandler.runWithScissors(()-> setUp(context),  0 /* timeout */);
+    }
+
+    private void setUp(Context context) {
+        mPhoneWindowManager = spy(new PhoneWindowManager());
+        mContext = spy(context);
+
+        // Use stubOnly() to reduce memory usage if it doesn't need verification.
+        final MockSettings spyStubOnly = withSettings().stubOnly()
+                .defaultAnswer(CALLS_REAL_METHODS);
+        // Return mocked services: LocalServices.getService
+        mMockitoSession = mockitoSession()
+                .mockStatic(LocalServices.class, spyStubOnly)
+                .startMocking();
+
+        doReturn(mWindowManagerInternal).when(
+                () -> LocalServices.getService(eq(WindowManagerInternal.class)));
+        doReturn(mActivityManagerInternal).when(
+                () -> LocalServices.getService(eq(ActivityManagerInternal.class)));
+        doReturn(mActivityTaskManagerInternal).when(
+                () -> LocalServices.getService(eq(ActivityTaskManagerInternal.class)));
+        doReturn(mInputManagerInternal).when(
+                () -> LocalServices.getService(eq(InputManagerInternal.class)));
+        doReturn(mDreamManagerInternal).when(
+                () -> LocalServices.getService(eq(DreamManagerInternal.class)));
+        doReturn(mPowerManagerInternal).when(
+                () -> LocalServices.getService(eq(PowerManagerInternal.class)));
+        doReturn(mDisplayManagerInternal).when(
+                () -> LocalServices.getService(eq(DisplayManagerInternal.class)));
+        doReturn(mGestureLauncherService).when(
+                () -> LocalServices.getService(eq(GestureLauncherService.class)));
+        doReturn(null).when(() -> LocalServices.getService(eq(VrManagerInternal.class)));
+        doReturn(null).when(() -> LocalServices.getService(eq(AutofillManagerInternal.class)));
+
+        doReturn(mAppOpsManager).when(mContext).getSystemService(eq(AppOpsManager.class));
+        doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
+        doReturn(mPackageManager).when(mContext).getPackageManager();
+        doReturn(false).when(mPackageManager).hasSystemFeature(any());
+        try {
+            doThrow(new PackageManager.NameNotFoundException("test")).when(mPackageManager)
+                    .getActivityInfo(any(), anyInt());
+            doReturn(new String[] { "testPackage" }).when(mPackageManager)
+                    .canonicalToCurrentPackageNames(any());
+        } catch (PackageManager.NameNotFoundException ignored) { }
+
+        doReturn(mTelecomManager).when(mContext).getSystemService(eq(Context.TELECOM_SERVICE));
+        doReturn(mNotificationManager).when(mContext)
+                .getSystemService(eq(NotificationManager.class));
+        doReturn(mVibrator).when(mContext).getSystemService(eq(Context.VIBRATOR_SERVICE));
+
+        final PowerManager.WakeLock wakeLock = mock(PowerManager.WakeLock.class);
+        doReturn(wakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+        doReturn(mPowerManager).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
+        doReturn(true).when(mPowerManager).isInteractive();
+
+        doReturn(mDisplay).when(mDisplayManager).getDisplay(eq(DEFAULT_DISPLAY));
+        doReturn(STATE_ON).when(mDisplay).getState();
+        doReturn(true).when(mDisplayPolicy).isAwake();
+        doNothing().when(mDisplayPolicy).takeScreenshot(anyInt(), anyInt());
+        doReturn(mDisplayPolicy).when(mDisplayRotation).getDisplayPolicy();
+        doReturn(mScreenOnListener).when(mDisplayPolicy).getScreenOnListener();
+        mPhoneWindowManager.setDefaultDisplay(new WindowManagerPolicy.DisplayContentInfo() {
+            @Override
+            public DisplayRotation getDisplayRotation() {
+                return mDisplayRotation;
+            }
+            @Override
+            public Display getDisplay() {
+                return mDisplay;
+            }
+        });
+
+        doNothing().when(mPhoneWindowManager).initializeHdmiState();
+        doNothing().when(mPhoneWindowManager).updateSettings();
+        doNothing().when(mPhoneWindowManager).screenTurningOn(anyInt(), any());
+        doNothing().when(mPhoneWindowManager).screenTurnedOn(anyInt());
+        doNothing().when(mPhoneWindowManager).startedWakingUp(anyInt());
+        doNothing().when(mPhoneWindowManager).finishedWakingUp(anyInt());
+
+        mPhoneWindowManager.init(new TestInjector(mContext, mWindowManagerFuncsImpl));
+        mPhoneWindowManager.systemReady();
+        mPhoneWindowManager.systemBooted();
+
+        overrideLaunchAccessibility();
+    }
+
+    void tearDown() {
+        mHandlerThread.quitSafely();
+        mMockitoSession.finishMocking();
+    }
+
+    // Override accessibility setting and perform function.
+    private void overrideLaunchAccessibility() {
+        doReturn(true).when(mAccessibilityShortcutController)
+                .isAccessibilityShortcutAvailable(anyBoolean());
+        doNothing().when(mAccessibilityShortcutController).performAccessibilityShortcut();
+    }
+
+    int interceptKeyBeforeQueueing(KeyEvent event) {
+        return mPhoneWindowManager.interceptKeyBeforeQueueing(event, FLAG_INTERACTIVE);
+    }
+
+    long interceptKeyBeforeDispatching(KeyEvent event) {
+        return mPhoneWindowManager.interceptKeyBeforeDispatching(null /*focusedToken*/,
+                event, FLAG_INTERACTIVE);
+    }
+
+    void dispatchUnhandledKey(KeyEvent event) {
+        mPhoneWindowManager.dispatchUnhandledKey(null /*focusedToken*/, event, FLAG_INTERACTIVE);
+    }
+
+    void waitForIdle() {
+        mHandler.runWithScissors(() -> { }, 0 /* timeout */);
+    }
+
+    /**
+     * Below functions will override the setting or the policy behavior.
+     */
+    void overridePowerVolumeUp(int behavior) {
+        mPhoneWindowManager.mPowerVolUpBehavior = behavior;
+
+        // override mRingerToggleChord as mute so we could trigger the behavior.
+        if (behavior == POWER_VOLUME_UP_BEHAVIOR_MUTE) {
+            mPhoneWindowManager.mRingerToggleChord = VOLUME_HUSH_MUTE;
+            doReturn(mAudioManagerInternal).when(
+                    () -> LocalServices.getService(eq(AudioManagerInternal.class)));
+        }
+    }
+
+     // Override assist perform function.
+    void overrideLongPressOnPower(int behavior) {
+        mPhoneWindowManager.mLongPressOnPowerBehavior = behavior;
+
+        switch (behavior) {
+            case LONG_PRESS_POWER_NOTHING:
+            case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+            case LONG_PRESS_POWER_SHUT_OFF:
+            case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
+            case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST:
+                break;
+            case LONG_PRESS_POWER_ASSISTANT:
+                doNothing().when(mPhoneWindowManager).sendCloseSystemWindows();
+                doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
+                doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt());
+                doReturn(mSearchManager).when(mContext)
+                        .getSystemService(eq(Context.SEARCH_SERVICE));
+                mPhoneWindowManager.mLongPressOnPowerAssistantTimeoutMs = 500;
+                break;
+        }
+    }
+
+    void overrideDisplayState(int state) {
+        doReturn(state).when(mDisplay).getState();
+        Mockito.reset(mPowerManager);
+    }
+
+    void overrideIncallPowerBehavior(int behavior) {
+        mPhoneWindowManager.mIncallPowerBehavior = behavior;
+        setPhoneCallIsInProgress();
+    }
+
+    void setPhoneCallIsInProgress() {
+        // Let device has an ongoing phone call.
+        doReturn(false).when(mTelecomManager).isRinging();
+        doReturn(true).when(mTelecomManager).isInCall();
+        doReturn(true).when(mTelecomManager).endCall();
+    }
+
+    /**
+     * Below functions will check the policy behavior could be invoked.
+     */
+    void assertTakeScreenshotCalled() {
+        waitForIdle();
+        verify(mDisplayPolicy, timeout(SHORTCUT_KEY_DELAY_MILLIS))
+                .takeScreenshot(anyInt(), anyInt());
+    }
+
+    void assertShowGlobalActionsCalled() {
+        waitForIdle();
+        verify(mPhoneWindowManager).showGlobalActions();
+        verify(mGlobalActions, timeout(SHORTCUT_KEY_DELAY_MILLIS))
+                .showDialog(anyBoolean(), anyBoolean());
+        verify(mPowerManager, timeout(SHORTCUT_KEY_DELAY_MILLIS))
+                .userActivity(anyLong(), anyBoolean());
+    }
+
+    void assertVolumeMute() {
+        waitForIdle();
+        verify(mAudioManagerInternal, timeout(SHORTCUT_KEY_DELAY_MILLIS))
+                .silenceRingerModeInternal(eq("volume_hush"));
+    }
+
+    void assertAccessibilityKeychordCalled() {
+        waitForIdle();
+        verify(mAccessibilityShortcutController,
+                timeout(SHORTCUT_KEY_DELAY_MILLIS)).performAccessibilityShortcut();
+    }
+
+    void assertPowerSleep() {
+        waitForIdle();
+        verify(mPowerManager,
+                timeout(SHORTCUT_KEY_DELAY_MILLIS)).goToSleep(anyLong(), anyInt(), anyInt());
+    }
+
+    void assertPowerWakeUp() {
+        waitForIdle();
+        verify(mPowerManager,
+                timeout(SHORTCUT_KEY_DELAY_MILLIS)).wakeUp(anyLong(), anyInt(), anyString());
+    }
+
+    void assertNoPowerSleep() {
+        waitForIdle();
+        verify(mPowerManager, never()).goToSleep(anyLong(), anyInt(), anyInt());
+    }
+
+    void assertCameraLaunch() {
+        waitForIdle();
+        // GestureLauncherService should receive interceptPowerKeyDown twice.
+        verify(mGestureLauncherService, times(2))
+                .interceptPowerKeyDown(any(), anyBoolean(), any());
+    }
+
+    void assertAssistLaunch() {
+        waitForIdle();
+        verify(mSearchManager, timeout(SHORTCUT_KEY_DELAY_MILLIS)).launchAssist(any());
+    }
+}
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 4449483..333be7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -158,7 +158,6 @@
 
 import com.android.internal.R;
 import com.android.server.wm.ActivityRecord.State;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -552,9 +551,9 @@
         final Rect insets = new Rect();
         final DisplayInfo displayInfo = task.mDisplayContent.getDisplayInfo();
         final DisplayPolicy policy = task.mDisplayContent.getDisplayPolicy();
-        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
-                displayInfo.logicalHeight, WmDisplayCutout.NO_CUTOUT, insets);
-        policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
+
+        insets.set(policy.getDecorInsetsInfo(displayInfo.rotation, displayInfo.logicalWidth,
+                displayInfo.logicalHeight).mConfigInsets);
         Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
 
         final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
@@ -594,9 +593,8 @@
         final Rect insets = new Rect();
         final DisplayInfo displayInfo = rootTask.mDisplayContent.getDisplayInfo();
         final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy();
-        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
-                displayInfo.logicalHeight, WmDisplayCutout.NO_CUTOUT, insets);
-        policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation);
+        insets.set(policy.getDecorInsetsInfo(displayInfo.rotation, displayInfo.logicalWidth,
+                displayInfo.logicalHeight).mConfigInsets);
         Task.intersectWithInsetsIfFits(stableRect, stableRect, insets);
 
         final boolean isScreenPortrait = stableRect.width() <= stableRect.height();
@@ -2869,6 +2867,7 @@
                 mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
         fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height));
         task.addChild(taskFragment1, POSITION_TOP);
+        assertEquals(task, activity1.mStartingData.mAssociatedTask);
 
         final TaskFragment taskFragment2 = new TaskFragment(
                 mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
@@ -2890,7 +2889,6 @@
                 eq(task.mSurfaceControl));
         assertEquals(activity1.mStartingData, startingWindow.mStartingData);
         assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent());
-        assertEquals(task, activity1.mStartingData.mAssociatedTask);
         assertEquals(taskFragment1.getBounds(), activity1.getBounds());
         // The activity was resized by task fragment, but starting window must still cover the task.
         assertEquals(taskBounds, activity1.mStartingWindow.getBounds());
@@ -2898,7 +2896,6 @@
         // The starting window is only removed when all embedded activities are drawn.
         final WindowState activityWindow = mock(WindowState.class);
         activity1.onFirstWindowDrawn(activityWindow);
-        assertNotNull(activity1.mStartingWindow);
         activity2.onFirstWindowDrawn(activityWindow);
         assertNull(activity1.mStartingWindow);
     }
@@ -2987,31 +2984,28 @@
     }
 
     @Test
-    public void testCloseToSquareFixedOrientationPortrait() {
+    public void testCloseToSquareFixedOrientation() {
         // create a square display
         final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
                 .setSystemDecorations(true).build();
+        // 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
-        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+        ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
                 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).build();
 
-        // check that both the configuration and app bounds are portrait
+        // The available space could be landscape because of decor insets, but the configuration
+        // should still respect the requested portrait orientation.
         assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
         assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width()
                 <= activity.getConfiguration().windowConfiguration.getAppBounds().height());
-    }
-
-    @Test
-    public void testCloseToSquareFixedOrientationLandscape() {
-        // create a square display
-        final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000)
-                .setSystemDecorations(true).build();
-        final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
 
         // create a fixed landscape activity
-        final ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task)
+        activity = new ActivityBuilder(mAtm).setTask(task)
                 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE).build();
 
         // check that both the configuration and app bounds are landscape
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 017de0f..2b0e76c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -35,6 +35,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
@@ -66,6 +67,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -100,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;
 
@@ -147,6 +149,9 @@
     @Before
     public void setUp() throws Exception {
         mController = mock(ActivityStartController.class);
+        BackgroundActivityStartController balController =
+                new BackgroundActivityStartController(mAtm, mSupervisor);
+        doReturn(balController).when(mController).getBackgroundActivityLaunchController();
         mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
         clearInvocations(mActivityMetricsLogger);
     }
@@ -208,10 +213,13 @@
             int expectedResult) {
         final ActivityTaskManagerService service = mAtm;
         final IPackageManager packageManager = mock(IPackageManager.class);
-        final ActivityStartController controller = mock(ActivityStartController.class);
 
-        final ActivityStarter starter = new ActivityStarter(controller, service,
-                service.mTaskSupervisor, mock(ActivityStartInterceptor.class));
+        final ActivityStarter starter =
+                new ActivityStarter(
+                        mController,
+                        service,
+                        service.mTaskSupervisor,
+                        mock(ActivityStartInterceptor.class));
         prepareStarter(launchFlags);
         final IApplicationThread caller = mock(IApplicationThread.class);
         final WindowProcessListener listener = mock(WindowProcessListener.class);
@@ -1404,6 +1412,39 @@
                 canEmbedActivity(taskFragment, starting, task));
     }
 
+    @Test
+    public void testRecordActivityMovementBeforeDeliverToTop() {
+        final Task task = new TaskBuilder(mAtm.mTaskSupervisor).build();
+        final ActivityRecord activityBot = new ActivityBuilder(mAtm).setTask(task).build();
+        final ActivityRecord activityTop = new ActivityBuilder(mAtm).setTask(task).build();
+
+        activityBot.setVisible(false);
+        activityBot.mVisibleRequested = false;
+
+        assertTrue(activityTop.isVisible());
+        assertTrue(activityTop.mVisibleRequested);
+
+        final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
+                        | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
+        starter.mStartActivity = activityBot;
+        task.inRecents = true;
+        starter.setInTask(task);
+        starter.getIntent().setComponent(activityBot.mActivityComponent);
+        final int result = starter.setReason("testRecordActivityMovement").execute();
+
+        assertEquals(START_DELIVERED_TO_TOP, result);
+        assertNotNull(starter.mMovedToTopActivity);
+
+        final ActivityStarter starter2 = prepareStarter(FLAG_ACTIVITY_REORDER_TO_FRONT
+                        | FLAG_ACTIVITY_NEW_TASK, false /* mockGetRootTask */);
+        starter2.setInTask(task);
+        starter2.getIntent().setComponent(activityBot.mActivityComponent);
+        final int result2 = starter2.setReason("testRecordActivityMovement").execute();
+
+        assertEquals(START_DELIVERED_TO_TOP, result2);
+        assertNull(starter2.mMovedToTopActivity);
+    }
+
     private static void startActivityInner(ActivityStarter starter, ActivityRecord target,
             ActivityRecord source, ActivityOptions options, Task inTask,
             TaskFragment inTaskFragment) {
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/DisplayPolicyInsetsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
index aa5a74e..0a59ae1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
@@ -25,13 +25,10 @@
 
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
 import android.view.DisplayInfo;
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.utils.WmDisplayCutout;
-
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ErrorCollector;
@@ -49,8 +46,7 @@
 
     @Test
     public void portrait() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_0, false /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */);
 
         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
         verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
@@ -59,8 +55,7 @@
 
     @Test
     public void portrait_withCutout() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_0, true /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */);
 
         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
         verifyNonDecorInsets(di, 0, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT);
@@ -69,8 +64,7 @@
 
     @Test
     public void landscape() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_90, false /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */);
 
         if (mDisplayPolicy.navigationBarCanMove()) {
             verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
@@ -85,8 +79,7 @@
 
     @Test
     public void landscape_withCutout() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_90, true /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */);
 
         if (mDisplayPolicy.navigationBarCanMove()) {
             verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
@@ -101,8 +94,7 @@
 
     @Test
     public void seascape() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_270, false /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */);
 
         if (mDisplayPolicy.navigationBarCanMove()) {
             verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
@@ -117,8 +109,7 @@
 
     @Test
     public void seascape_withCutout() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_270, true /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */);
 
         if (mDisplayPolicy.navigationBarCanMove()) {
             verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
@@ -133,8 +124,7 @@
 
     @Test
     public void upsideDown() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_180, false /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */);
 
         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
         verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
@@ -143,34 +133,32 @@
 
     @Test
     public void upsideDown_withCutout() {
-        final Pair<DisplayInfo, WmDisplayCutout> di =
-                displayInfoForRotation(ROTATION_180, true /* withCutout */);
+        final DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */);
 
         verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
         verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
         verifyConsistency(di);
     }
 
-    private void verifyStableInsets(Pair<DisplayInfo, WmDisplayCutout> diPair, int left, int top,
+    private void verifyStableInsets(DisplayInfo di, int left, int top,
             int right, int bottom) {
-        mErrorCollector.checkThat("stableInsets", getStableInsetsLw(diPair.first, diPair.second),
+        mErrorCollector.checkThat("stableInsets", getStableInsets(di),
                 equalTo(new Rect(left, top, right, bottom)));
     }
 
-    private void verifyNonDecorInsets(Pair<DisplayInfo, WmDisplayCutout> diPair, int left, int top,
+    private void verifyNonDecorInsets(DisplayInfo di, int left, int top,
             int right, int bottom) {
         mErrorCollector.checkThat("nonDecorInsets",
-                getNonDecorInsetsLw(diPair.first, diPair.second), equalTo(new Rect(
-                left, top, right, bottom)));
+                getNonDecorInsets(di), equalTo(new Rect(left, top, right, bottom)));
     }
 
-    private void verifyConsistency(Pair<DisplayInfo, WmDisplayCutout> diPair) {
-        final DisplayInfo di = diPair.first;
-        final WmDisplayCutout cutout = diPair.second;
-        verifyConsistency("configDisplay", di, getStableInsetsLw(di, cutout),
-                getConfigDisplayWidth(di, cutout), getConfigDisplayHeight(di, cutout));
-        verifyConsistency("nonDecorDisplay", di, getNonDecorInsetsLw(di, cutout),
-                getNonDecorDisplayWidth(di, cutout), getNonDecorDisplayHeight(di, cutout));
+    private void verifyConsistency(DisplayInfo  di) {
+        final DisplayPolicy.DecorInsets.Info info = mDisplayPolicy.getDecorInsetsInfo(
+                di.rotation, di.logicalWidth, di.logicalHeight);
+        verifyConsistency("configDisplay", di, info.mConfigInsets,
+                info.mConfigFrame.width(), info.mConfigFrame.height());
+        verifyConsistency("nonDecorDisplay", di, info.mNonDecorInsets,
+                info.mNonDecorFrame.width(), info.mNonDecorFrame.height());
     }
 
     private void verifyConsistency(String what, DisplayInfo di, Rect insets, int width,
@@ -181,42 +169,18 @@
                 equalTo(di.logicalHeight - insets.top - insets.bottom));
     }
 
-    private Rect getStableInsetsLw(DisplayInfo di, WmDisplayCutout cutout) {
-        Rect result = new Rect();
-        mDisplayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
-                cutout, result);
-        return result;
+    private Rect getStableInsets(DisplayInfo di) {
+        return mDisplayPolicy.getDecorInsetsInfo(
+                di.rotation, di.logicalWidth, di.logicalHeight).mConfigInsets;
     }
 
-    private Rect getNonDecorInsetsLw(DisplayInfo di, WmDisplayCutout cutout) {
-        Rect result = new Rect();
-        mDisplayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
-                cutout, result);
-        return result;
+    private Rect getNonDecorInsets(DisplayInfo di) {
+        return mDisplayPolicy.getDecorInsetsInfo(
+                di.rotation, di.logicalWidth, di.logicalHeight).mNonDecorInsets;
     }
 
-    private int getNonDecorDisplayWidth(DisplayInfo di, WmDisplayCutout cutout) {
-        return mDisplayPolicy.getNonDecorDisplayFrame(di.logicalWidth, di.logicalHeight,
-                di.rotation, cutout).width();
-    }
-
-    private int getNonDecorDisplayHeight(DisplayInfo di, WmDisplayCutout cutout) {
-        return mDisplayPolicy.getNonDecorDisplayFrame(di.logicalWidth, di.logicalHeight,
-                di.rotation, cutout).height();
-    }
-
-    private int getConfigDisplayWidth(DisplayInfo di, WmDisplayCutout cutout) {
-        return mDisplayPolicy.getConfigDisplaySize(di.logicalWidth, di.logicalHeight,
-                di.rotation, cutout).x;
-    }
-
-    private int getConfigDisplayHeight(DisplayInfo di, WmDisplayCutout cutout) {
-        return mDisplayPolicy.getConfigDisplaySize(di.logicalWidth, di.logicalHeight,
-                di.rotation, cutout).y;
-    }
-
-    private static Pair<DisplayInfo, WmDisplayCutout> displayInfoForRotation(int rotation,
-            boolean withDisplayCutout) {
-        return displayInfoAndCutoutForRotation(rotation, withDisplayCutout, false);
+    private DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
+        return displayInfoAndCutoutForRotation(
+                rotation, withDisplayCutout, false /* isLongEdgeCutout */);
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 6bdc2e3..70b68c7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -41,7 +41,6 @@
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
-import android.util.Pair;
 import android.view.DisplayInfo;
 import android.view.InsetsFrameProvider;
 import android.view.InsetsState;
@@ -50,8 +49,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.utils.WmDisplayCutout;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -123,7 +120,7 @@
     private void updateDisplayFrames() {
         mFrames = createDisplayFrames(
                 mDisplayContent.getInsetsStateController().getRawInsetsState());
-        mDisplayBounds.set(0, 0, mFrames.mDisplayWidth, mFrames.mDisplayHeight);
+        mDisplayBounds.set(0, 0, mFrames.mWidth, mFrames.mHeight);
         mDisplayContent.mDisplayFrames = mFrames;
         mDisplayContent.setBounds(mDisplayBounds);
         mDisplayPolicy.layoutWindowLw(mNavBarWindow, null, mFrames);
@@ -131,13 +128,13 @@
     }
 
     private DisplayFrames createDisplayFrames(InsetsState insetsState) {
-        final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
+        final DisplayInfo info = displayInfoAndCutoutForRotation(mRotation,
                 mHasDisplayCutout, mIsLongEdgeDisplayCutout);
         final RoundedCorners roundedCorners = mHasRoundedCorners
                 ? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
                 : RoundedCorners.NO_ROUNDED_CORNERS;
-        return new DisplayFrames(mDisplayContent.getDisplayId(),
-                insetsState, info.first, info.second, roundedCorners, new PrivacyIndicatorBounds());
+        return new DisplayFrames(insetsState, info,
+                info.displayCutout, roundedCorners, new PrivacyIndicatorBounds());
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 9cc665b..262b141 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.DisplayCutout.NO_CUTOUT;
 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -35,13 +36,12 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.wm.utils.WmDisplayCutout.NO_CUTOUT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -286,10 +286,18 @@
                 DisplayPolicy.isOverlappingWithNavBar(targetWin));
     }
 
-    private WindowState createNavigationBarWindow() {
-        final WindowState win = createWindow(null, TYPE_NAVIGATION_BAR, "NavigationBar");
-        win.mHasSurface = true;
-        return win;
+    @Test
+    public void testUpdateDisplayConfigurationByDecor() {
+        final WindowState navbar = createNavBarWithProvidedInsets(mDisplayContent);
+        final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+        final DisplayInfo di = mDisplayContent.getDisplayInfo();
+        final int prevScreenHeightDp = mDisplayContent.getConfiguration().screenHeightDp;
+        assertTrue(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
+        assertEquals(NAV_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation,
+                di.logicalWidth, di.logicalHeight).mConfigInsets.bottom);
+        mDisplayContent.sendNewConfiguration();
+        assertNotEquals(prevScreenHeightDp, mDisplayContent.getConfiguration().screenHeightDp);
+        assertFalse(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
     }
 
     @SetupWindows(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
@@ -307,7 +315,7 @@
         mNavBarWindow.getControllableInsetProvider().setServerVisible(true);
         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         mImeWindow.mAboveInsetsState.set(state);
-        mDisplayContent.mDisplayFrames = new DisplayFrames(mDisplayContent.getDisplayId(),
+        mDisplayContent.mDisplayFrames = new DisplayFrames(
                 state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
 
         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 97b1c91..fe890d5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -30,25 +30,14 @@
 import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
 
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
 import android.graphics.Matrix;
 import android.graphics.RectF;
 import android.os.Binder;
-import android.os.IBinder;
-import android.testing.TestableResources;
-import android.util.Pair;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.WindowManagerGlobal;
 
-import com.android.internal.R;
-import com.android.server.wm.utils.WmDisplayCutout;
-
 import org.junit.Before;
 
 public class DisplayPolicyTestsBase extends WindowTestsBase {
@@ -69,23 +58,8 @@
 
         mDisplayPolicy = mDisplayContent.getDisplayPolicy();
         spyOn(mDisplayPolicy);
-
-        final TestContextWrapper context = new TestContextWrapper(
-                mDisplayPolicy.getContext(), mDisplayPolicy.getCurrentUserResources());
-        final TestableResources resources = context.getResourceMocker();
-        resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
-        resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
-        resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
-        resources.addOverride(R.dimen.navigation_bar_frame_height_landscape, NAV_BAR_HEIGHT);
-        resources.addOverride(R.dimen.navigation_bar_frame_height, NAV_BAR_HEIGHT);
-        doReturn(STATUS_BAR_HEIGHT).when(mDisplayPolicy).getStatusBarHeightForRotation(anyInt());
-        doReturn(resources.getResources()).when(mDisplayPolicy).getCurrentUserResources();
         doReturn(true).when(mDisplayPolicy).hasNavigationBar();
         doReturn(true).when(mDisplayPolicy).hasStatusBar();
-
-        mDisplayContent.getDisplayRotation().configure(DISPLAY_WIDTH, DISPLAY_HEIGHT);
-        mDisplayPolicy.onConfigurationChanged();
-
         addWindow(mStatusBarWindow);
         addWindow(mNavBarWindow);
 
@@ -101,24 +75,20 @@
         win.mHasSurface = true;
     }
 
-    static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
-            boolean withDisplayCutout, boolean isLongEdgeCutout) {
-        final DisplayInfo info = new DisplayInfo();
-        WmDisplayCutout cutout = WmDisplayCutout.NO_CUTOUT;
-
+    DisplayInfo displayInfoAndCutoutForRotation(int rotation, boolean withDisplayCutout,
+            boolean isLongEdgeCutout) {
+        final DisplayInfo info = mDisplayContent.getDisplayInfo();
         final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
         info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
         info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
         info.rotation = rotation;
-        if (withDisplayCutout) {
-            cutout = WmDisplayCutout.computeSafeInsets(
-                    displayCutoutForRotation(rotation, isLongEdgeCutout), info.logicalWidth,
-                    info.logicalHeight);
-            info.displayCutout = cutout.getDisplayCutout();
-        } else {
-            info.displayCutout = null;
-        }
-        return Pair.create(info, cutout);
+        mDisplayContent.mInitialDisplayCutout = withDisplayCutout
+                ? displayCutoutForRotation(ROTATION_0, isLongEdgeCutout)
+                : DisplayCutout.NO_CUTOUT;
+        info.displayCutout = mDisplayContent.calculateDisplayCutoutForRotation(rotation);
+        mDisplayContent.updateBaseDisplayMetrics(DISPLAY_WIDTH, DISPLAY_HEIGHT,
+                info.logicalDensityDpi, info.physicalXDpi, info.physicalYDpi);
+        return info;
     }
 
     private static DisplayCutout displayCutoutForRotation(int rotation, boolean isLongEdgeCutout) {
@@ -152,33 +122,4 @@
         return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
                 (int) rectF.right, (int) rectF.bottom, pos);
     }
-
-    static class TestContextWrapper extends ContextWrapper {
-        private final TestableResources mResourceMocker;
-
-        TestContextWrapper(Context targetContext, Resources targetResources) {
-            super(targetContext);
-            mResourceMocker = new TestableResources(targetResources);
-        }
-
-        @Override
-        public int checkPermission(String permission, int pid, int uid) {
-            return PackageManager.PERMISSION_GRANTED;
-        }
-
-        @Override
-        public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
-            return PackageManager.PERMISSION_GRANTED;
-        }
-
-        @Override
-        public Resources getResources() {
-            return mResourceMocker.getResources();
-        }
-
-        TestableResources getResourceMocker() {
-            return mResourceMocker;
-        }
-    }
-
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index 892b5f9..89f7111 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -20,6 +20,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.DisplayCutout.NO_CUTOUT;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DEFAULT;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_DISABLED;
 import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
@@ -68,7 +69,6 @@
 import com.android.server.UiThread;
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -1008,7 +1008,7 @@
             mMockDisplayContent = mock(DisplayContent.class);
             mMockDisplayContent.isDefaultDisplay = mIsDefaultDisplay;
             when(mMockDisplayContent.calculateDisplayCutoutForRotation(anyInt()))
-                    .thenReturn(WmDisplayCutout.NO_CUTOUT);
+                    .thenReturn(NO_CUTOUT);
             when(mMockDisplayContent.getDefaultTaskDisplayArea())
                     .thenReturn(mock(TaskDisplayArea.class));
             when(mMockDisplayContent.getWindowConfiguration())
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/PossibleDisplayInfoMapperTests.java b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
index 8b0a540..58b0e16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
@@ -36,6 +36,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Set;
 
 
@@ -88,7 +90,8 @@
         mPossibleDisplayInfo.add(mDefaultDisplayInfo);
         mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
 
-        Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
+        List<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(
+                DEFAULT_DISPLAY);
         // An entry for rotation 0, for a display that can be in a single state.
         assertThat(displayInfos.size()).isEqualTo(1);
         assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
@@ -105,9 +108,10 @@
         mPossibleDisplayInfo.add(mSecondDisplayInfo);
         mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
 
-        Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
-        Set<DisplayInfo> defaultDisplayInfos = new ArraySet<>();
-        Set<DisplayInfo> secondDisplayInfos = new ArraySet<>();
+        List<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(
+                DEFAULT_DISPLAY);
+        List<DisplayInfo> defaultDisplayInfos = new ArrayList<>();
+        List<DisplayInfo> secondDisplayInfos = new ArrayList<>();
         for (DisplayInfo di : displayInfos) {
             if ((di.flags & FLAG_PRESENTATION) != 0) {
                 secondDisplayInfos.add(di);
@@ -137,12 +141,13 @@
         mPossibleDisplayInfo.add(mSecondDisplayInfo);
         mDisplayInfoMapper.updatePossibleDisplayInfos(mSecondDisplayInfo.displayId);
 
-        Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
+        List<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(
+                DEFAULT_DISPLAY);
         // An entry for rotation 0, for the default display.
         assertThat(displayInfos).hasSize(1);
         assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
 
-        Set<DisplayInfo> secondStateEntries =
+        List<DisplayInfo> secondStateEntries =
                 mDisplayInfoMapper.getPossibleDisplayInfos(mSecondDisplayInfo.displayId);
         // An entry for rotation 0, for the second display.
         assertThat(secondStateEntries).hasSize(1);
@@ -157,7 +162,7 @@
         outDisplayInfo.logicalHeight = logicalBounds.height();
     }
 
-    private static void assertPossibleDisplayInfoEntries(Set<DisplayInfo> displayInfos,
+    private static void assertPossibleDisplayInfoEntries(List<DisplayInfo> displayInfos,
             DisplayInfo expectedDisplayInfo) {
         for (DisplayInfo displayInfo : displayInfos) {
             assertThat(displayInfo.displayId).isEqualTo(expectedDisplayInfo.displayId);
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/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 6d33aaf..646f43c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1640,6 +1640,75 @@
     }
 
     @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN})
+    public void testOverrideMinAspectRatioExcludePortraitFullscreen() {
+        setUpDisplaySizeWithApp(2600, 1600);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
+
+        // Create a size compat activity on the same task.
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setUid(android.os.Process.myUid())
+                .build();
+
+        // Non-resizable portrait activity
+        prepareUnresizable(activity, 0f, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+
+        // At first, OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply, because the
+        // display is in landscape
+        assertEquals(1600, activity.getBounds().height());
+        assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                activity.getBounds().width(), 0.5);
+
+        rotateDisplay(activity.mDisplayContent, ROTATION_90);
+        prepareUnresizable(activity, /* maxAspect */ 0, SCREEN_ORIENTATION_PORTRAIT);
+
+        // Now the display is in portrait fullscreen, so the override is applied making the content
+        // fullscreen
+        assertEquals(activity.getBounds(), activity.mDisplayContent.getBounds());
+    }
+
+    @Test
+    @EnableCompatChanges({ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE,
+            ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN})
+    public void testOverrideMinAspectRatioExcludePortraitFullscreenNotApplied() {
+        // In this test, the activity is not in fullscreen, so the override is not applied
+        setUpDisplaySizeWithApp(2600, 1600);
+        mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
+        mActivity.mWmService.mLetterboxConfiguration.setFixedOrientationLetterboxAspectRatio(1.33f);
+
+        // Create a size compat activity on the same task.
+        final ActivityRecord activity = new ActivityBuilder(mAtm)
+                .setTask(mTask)
+                .setComponent(ComponentName.createRelative(mContext,
+                        SizeCompatTests.class.getName()))
+                .setUid(android.os.Process.myUid())
+                .build();
+
+        final TestSplitOrganizer organizer =
+                new TestSplitOrganizer(mAtm, activity.getDisplayContent());
+
+        // Move first activity to split screen which takes half of the screen.
+        organizer.mPrimary.setBounds(0, 0, 1300, 1600);
+        organizer.putTaskToPrimary(mTask, true);
+
+        // Non-resizable portrait activity
+        prepareUnresizable(activity, /* maxAspect */ 0, SCREEN_ORIENTATION_PORTRAIT);
+
+        // OVERRIDE_MIN_ASPECT_RATIO_PORTRAIT_FULLSCREEN does not apply here because the
+        // display is not in fullscreen, so OVERRIDE_MIN_ASPECT_RATIO_LARGE applies instead
+        assertEquals(1600, activity.getBounds().height());
+        assertEquals(1600 / ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE,
+                activity.getBounds().width(), 0.5);
+    }
+
+    @Test
     public void testSplitAspectRatioForUnresizableLandscapeApps() {
         // Set up a display in portrait and ignoring orientation request.
         int screenWidth = 1400;
@@ -3064,8 +3133,8 @@
     }
 
     private static void resizeDisplay(DisplayContent displayContent, int width, int height) {
-        displayContent.mBaseDisplayWidth = width;
-        displayContent.mBaseDisplayHeight = height;
+        displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity,
+                displayContent.mBaseDisplayPhysicalXDpi, displayContent.mBaseDisplayPhysicalYDpi);
         final Configuration c = new Configuration();
         displayContent.computeScreenConfiguration(c);
         displayContent.onRequestedOverrideConfigurationChanged(c);
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 ab7e8ea..9e6c4c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -235,6 +235,7 @@
         doReturn(pm).when(mContext).getSystemService(eq(Context.POWER_SERVICE));
         mStubbedWakeLock = createStubbedWakeLock(false /* needVerification */);
         doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString());
+        doReturn(mStubbedWakeLock).when(pm).newWakeLock(anyInt(), anyString(), anyInt());
 
         // DisplayManagerInternal
         final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 24cdc0f..9bdf750 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -20,6 +20,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_OP_TYPE;
 import static android.window.TaskFragmentOrganizer.KEY_ERROR_CALLBACK_THROWABLE;
+import static android.window.TaskFragmentOrganizer.getTransitionType;
 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;
@@ -49,8 +50,8 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -78,7 +79,6 @@
 import android.window.TaskFragmentTransaction;
 import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransactionCallback;
 
 import androidx.test.filters.SmallTest;
 
@@ -136,6 +136,7 @@
         mTaskFragment =
                 new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
         mTransaction = new WindowContainerTransaction();
+        mTransaction.setTaskFragmentOrganizer(mIOrganizer);
         mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
         mDefinition = new RemoteAnimationDefinition();
         mErrorToken = new Binder();
@@ -155,11 +156,16 @@
         doReturn(new Configuration()).when(mTaskFragmentInfo).getConfiguration();
 
         // To prevent it from calling the real server.
-        doNothing().when(mOrganizer).onTransactionHandled(any(), any());
+        doNothing().when(mOrganizer).applyTransaction(any(), anyInt(), anyBoolean());
+        doNothing().when(mOrganizer).onTransactionHandled(any(), any(), anyInt(), anyBoolean());
+
+        mController.registerOrganizer(mIOrganizer);
     }
 
     @Test
     public void testCallTaskFragmentCallbackWithoutRegister_throwsException() {
+        mController.unregisterOrganizer(mIOrganizer);
+
         doReturn(mTask).when(mTaskFragment).getTask();
 
         assertThrows(IllegalArgumentException.class, () -> mController
@@ -175,8 +181,6 @@
 
     @Test
     public void testOnTaskFragmentAppeared() {
-        mController.registerOrganizer(mIOrganizer);
-
         // No-op when the TaskFragment is not attached.
         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
         mController.dispatchPendingEvents();
@@ -194,7 +198,6 @@
 
     @Test
     public void testOnTaskFragmentInfoChanged() {
-        mController.registerOrganizer(mIOrganizer);
         setupMockParent(mTaskFragment, mTask);
 
         // No-op if onTaskFragmentAppeared is not called yet.
@@ -233,8 +236,6 @@
 
     @Test
     public void testOnTaskFragmentVanished() {
-        mController.registerOrganizer(mIOrganizer);
-
         mTaskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentVanished(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
         mController.dispatchPendingEvents();
@@ -244,7 +245,6 @@
 
     @Test
     public void testOnTaskFragmentVanished_clearUpRemaining() {
-        mController.registerOrganizer(mIOrganizer);
         setupMockParent(mTaskFragment, mTask);
 
         // Not trigger onTaskFragmentAppeared.
@@ -270,7 +270,6 @@
 
     @Test
     public void testOnTaskFragmentParentInfoChanged() {
-        mController.registerOrganizer(mIOrganizer);
         setupMockParent(mTaskFragment, mTask);
         mTask.getConfiguration().smallestScreenWidthDp = 10;
 
@@ -317,7 +316,6 @@
     public void testOnTaskFragmentError() {
         final Throwable exception = new IllegalArgumentException("Test exception");
 
-        mController.registerOrganizer(mIOrganizer);
         mController.onTaskFragmentError(mTaskFragment.getTaskFragmentOrganizer(),
                 mErrorToken, null /* taskFragment */, HIERARCHY_OP_TYPE_SET_ADJACENT_ROOTS,
                 exception);
@@ -332,7 +330,6 @@
         // Make sure the activity pid/uid is the same as the organizer caller.
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
-        mController.registerOrganizer(mIOrganizer);
         final ActivityRecord activity = createActivityRecord(mDisplayContent);
         final Task task = activity.getTask();
         activity.info.applicationInfo.uid = uid;
@@ -375,8 +372,6 @@
         mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
                 DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
         mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
-        mController.registerOrganizer(mIOrganizer);
-        mOrganizer.applyTransaction(mTransaction);
         final Task task = createTask(mDisplayContent);
         task.addChild(mTaskFragment, POSITION_TOP);
         final ActivityRecord activity = createActivityRecord(task);
@@ -404,7 +399,7 @@
         assertEquals(activity.intent, change.getActivityIntent());
         assertNotEquals(activity.token, change.getActivityToken());
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken());
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertEquals(mTaskFragment, activity.getTaskFragment());
         // The temporary token can only be used once.
@@ -414,7 +409,6 @@
 
     @Test
     public void testRegisterRemoteAnimations() {
-        mController.registerOrganizer(mIOrganizer);
         mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition);
 
         assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer, TASK_ID));
@@ -425,23 +419,7 @@
     }
 
     @Test
-    public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
-        mOrganizer.applyTransaction(mTransaction);
-
-        assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer());
-
-        mTransaction = new WindowContainerTransaction();
-        mOrganizer.applySyncTransaction(
-                mTransaction, mock(WindowContainerTransactionCallback.class));
-
-        assertEquals(mIOrganizer, mTransaction.getTaskFragmentOrganizer());
-    }
-
-    @Test
-    public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment()
-            throws RemoteException {
-        mOrganizer.applyTransaction(mTransaction);
-
+    public void testApplyTransaction_enforceConfigurationChangeOnOrganizedTaskFragment() {
         // Throw exception if the transaction is trying to change a window that is not organized by
         // the organizer.
         mTransaction.setBounds(mFragmentWindowToken, new Rect(0, 0, 100, 100));
@@ -457,10 +435,7 @@
 
 
     @Test
-    public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment()
-            throws RemoteException {
-        mController.registerOrganizer(mIOrganizer);
-        mOrganizer.applyTransaction(mTransaction);
+    public void testApplyTransaction_enforceHierarchyChange_deleteTaskFragment() {
         doReturn(true).when(mTaskFragment).isAttached();
 
         // Throw exception if the transaction is trying to change a window that is not organized by
@@ -486,13 +461,10 @@
     }
 
     @Test
-    public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots()
-            throws RemoteException {
-        mAtm.mTaskFragmentOrganizerController.registerOrganizer(mIOrganizer);
+    public void testApplyTransaction_enforceHierarchyChange_setAdjacentRoots() {
         final TaskFragment taskFragment2 =
                 new TaskFragment(mAtm, new Binder(), true /* createdByOrganizer */);
         final WindowContainerToken token2 = taskFragment2.mRemoteToken.toWindowContainerToken();
-        mOrganizer.applyTransaction(mTransaction);
 
         // Throw exception if the transaction is trying to change a window that is not organized by
         // the organizer.
@@ -513,9 +485,7 @@
     }
 
     @Test
-    public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
-            throws RemoteException {
-        mController.registerOrganizer(mIOrganizer);
+    public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
         final IBinder fragmentToken = new Binder();
 
@@ -526,11 +496,10 @@
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
         mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
                 null /* options */);
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         // Successfully created a TaskFragment.
-        final TaskFragment taskFragment = mAtm.mWindowOrganizerController
-                .getTaskFragment(fragmentToken);
+        final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
         assertNotNull(taskFragment);
         assertEquals(ownerActivity.getTask(), taskFragment.getTask());
     }
@@ -539,7 +508,6 @@
     public void testApplyTransaction_enforceTaskFragmentOrganized_startActivityInTaskFragment() {
         final Task task = createTask(mDisplayContent);
         final ActivityRecord ownerActivity = createActivityRecord(task);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .setFragmentToken(mFragmentToken)
@@ -562,7 +530,6 @@
     public void testApplyTransaction_enforceTaskFragmentOrganized_reparentActivityInTaskFragment() {
         final Task task = createTask(mDisplayContent);
         final ActivityRecord activity = createActivityRecord(task);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .setFragmentToken(mFragmentToken)
@@ -583,7 +550,6 @@
     @Test
     public void testApplyTransaction_enforceTaskFragmentOrganized_setAdjacentTaskFragments() {
         final Task task = createTask(mDisplayContent);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .setFragmentToken(mFragmentToken)
@@ -623,7 +589,6 @@
     @Test
     public void testApplyTransaction_enforceTaskFragmentOrganized_requestFocusOnTaskFragment() {
         final Task task = createTask(mDisplayContent);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .setFragmentToken(mFragmentToken)
@@ -642,44 +607,38 @@
     }
 
     @Test
-    public void testApplyTransaction_createTaskFragment_failForDifferentUid()
-            throws RemoteException {
-        mController.registerOrganizer(mIOrganizer);
+    public void testApplyTransaction_createTaskFragment_failForDifferentUid() {
         final ActivityRecord activity = createActivityRecord(mDisplayContent);
         final int uid = Binder.getCallingUid();
         final IBinder fragmentToken = new Binder();
         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
                 mOrganizerToken, fragmentToken, activity.token).build();
-        mOrganizer.applyTransaction(mTransaction);
         mTransaction.createTaskFragment(params);
 
         // Fail to create TaskFragment when the task uid is different from caller.
         activity.info.applicationInfo.uid = uid;
         activity.getTask().effectiveUid = uid + 1;
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
 
         // Fail to create TaskFragment when the task uid is different from owner activity.
         activity.info.applicationInfo.uid = uid + 1;
         activity.getTask().effectiveUid = uid;
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
 
         // Successfully created a TaskFragment for same uid.
         activity.info.applicationInfo.uid = uid;
         activity.getTask().effectiveUid = uid;
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
     }
 
     @Test
-    public void testApplyTransaction_enforceHierarchyChange_reparentChildren()
-            throws RemoteException {
-        mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
+    public void testApplyTransaction_enforceHierarchyChange_reparentChildren() {
         doReturn(true).when(mTaskFragment).isAttached();
 
         // Throw exception if the transaction is trying to change a window that is not organized by
@@ -699,14 +658,12 @@
     }
 
     @Test
-    public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate()
-            throws RemoteException {
+    public void testApplyTransaction_reparentActivityToTaskFragment_triggerLifecycleUpdate() {
         final Task task = createTask(mDisplayContent);
         final ActivityRecord activity = createActivityRecord(task);
         // Skip manipulate the SurfaceControl.
         doNothing().when(activity).setDropInputMode(anyInt());
         mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .setFragmentToken(mFragmentToken)
@@ -717,15 +674,13 @@
         doReturn(EMBEDDING_ALLOWED).when(mTaskFragment).isAllowedToEmbedActivity(activity);
         clearInvocations(mAtm.mRootWindowContainer);
 
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mAtm.mRootWindowContainer).resumeFocusedTasksTopActivities();
     }
 
     @Test
     public void testApplyTransaction_requestFocusOnTaskFragment() {
-        mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
         final Task task = createTask(mDisplayContent);
         final IBinder token0 = new Binder();
         final TaskFragment tf0 = new TaskFragmentBuilder(mAtm)
@@ -750,7 +705,7 @@
         final ActivityRecord activityInOtherTask = createActivityRecord(mDefaultDisplay);
         mDisplayContent.setFocusedApp(activityInOtherTask);
         mTransaction.requestFocusOnTaskFragment(token0);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertEquals(activityInOtherTask, mDisplayContent.mFocusedApp);
 
@@ -758,7 +713,7 @@
         activity0.setState(ActivityRecord.State.PAUSED, "test");
         activity1.setState(ActivityRecord.State.RESUMED, "test");
         mDisplayContent.setFocusedApp(activity1);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertEquals(activity1, mDisplayContent.mFocusedApp);
 
@@ -766,28 +721,29 @@
         // has a resumed activity.
         activity0.setState(ActivityRecord.State.RESUMED, "test");
         mDisplayContent.setFocusedApp(activity1);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertEquals(activity0, mDisplayContent.mFocusedApp);
     }
 
     @Test
     public void testApplyTransaction_skipTransactionForUnregisterOrganizer() {
+        mController.unregisterOrganizer(mIOrganizer);
         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
         final IBinder fragmentToken = new Binder();
 
         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
         createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
-        mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         // Nothing should happen as the organizer is not registered.
-        assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+        assertNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
 
         mController.registerOrganizer(mIOrganizer);
-        mAtm.mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         // Successfully created when the organizer is registered.
-        assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
+        assertNotNull(mWindowOrganizerController.getTaskFragment(fragmentToken));
     }
 
     @Test
@@ -799,13 +755,13 @@
 
         // Not allow to start activity in a TaskFragment that is in a PIP Task.
         mTransaction.startActivityInTaskFragment(
-                mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
+                        mFragmentToken, activity.token, new Intent(), null /* activityOptions */)
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mAtm.getActivityStartController(), never()).startActivityInTaskFragment(any(), any(),
                 any(), any(), anyInt(), anyInt(), any());
-        verify(mAtm.mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
+        verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
                 eq(mErrorToken), eq(mTaskFragment),
                 eq(HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT),
                 any(IllegalArgumentException.class));
@@ -820,7 +776,7 @@
         // Not allow to reparent activity to a TaskFragment that is in a PIP Task.
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
                 eq(mErrorToken), eq(mTaskFragment),
@@ -836,9 +792,9 @@
 
         // Not allow to set adjacent on a TaskFragment that is in a PIP Task.
         mTransaction.setAdjacentTaskFragments(mFragmentToken, null /* fragmentToken2 */,
-                null /* options */)
+                        null /* options */)
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
                 eq(mErrorToken), eq(mTaskFragment),
@@ -849,7 +805,6 @@
 
     @Test
     public void testTaskFragmentInPip_createTaskFragment() {
-        mController.registerOrganizer(mIOrganizer);
         final Task pipTask = createTask(mDisplayContent, WINDOWING_MODE_PINNED,
                 ACTIVITY_TYPE_STANDARD);
         final ActivityRecord activity = createActivityRecord(pipTask);
@@ -859,7 +814,7 @@
         // Not allow to create TaskFragment in a PIP Task.
         createTaskFragmentFromOrganizer(mTransaction, activity, fragmentToken);
         mTransaction.setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
                 eq(mErrorToken), eq(null), eq(HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT),
@@ -875,7 +830,7 @@
         // Not allow to delete a TaskFragment that is in a PIP Task.
         mTransaction.deleteTaskFragment(mFragmentWindowToken)
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         verify(mWindowOrganizerController).sendTaskFragmentOperationFailure(eq(mIOrganizer),
                 eq(mErrorToken), eq(mTaskFragment), eq(HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT),
@@ -885,7 +840,7 @@
         // Allow organizer to delete empty TaskFragment for cleanup.
         final Task task = mTaskFragment.getTask();
         mTaskFragment.removeChild(mTaskFragment.getTopMostActivity());
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertNull(mWindowOrganizerController.getTaskFragment(mFragmentToken));
         assertNull(task.getTopChild());
@@ -916,7 +871,6 @@
         doReturn(false).when(task).shouldBeVisible(any());
 
         // Sending events
-        mController.registerOrganizer(mIOrganizer);
         taskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
         mController.dispatchPendingEvents();
@@ -942,7 +896,6 @@
         taskFragment.setResumedActivity(null, "test");
 
         // Sending events
-        mController.registerOrganizer(mIOrganizer);
         taskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
         mController.dispatchPendingEvents();
@@ -977,7 +930,6 @@
         assertTrue(parentTask.shouldBeVisible(null));
 
         // Dispatch pending info changed event from creating the activity
-        mController.registerOrganizer(mIOrganizer);
         taskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
         mController.dispatchPendingEvents();
@@ -1013,7 +965,6 @@
         assertTrue(task.shouldBeVisible(null));
 
         // Dispatch pending info changed event from creating the activity
-        mController.registerOrganizer(mIOrganizer);
         taskFragment.mTaskFragmentAppearedSent = true;
         mController.onTaskFragmentInfoChanged(mIOrganizer, taskFragment);
         mController.dispatchPendingEvents();
@@ -1039,13 +990,11 @@
      * {@link WindowOrganizerController}.
      */
     @Test
-    public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment()
-            throws RemoteException {
-        mController.registerOrganizer(mIOrganizer);
+    public void testTaskFragmentRemoved_cleanUpEmbeddedTaskFragment() {
         final ActivityRecord ownerActivity = createActivityRecord(mDisplayContent);
         final IBinder fragmentToken = new Binder();
         createTaskFragmentFromOrganizer(mTransaction, ownerActivity, fragmentToken);
-        mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
         final TaskFragment taskFragment = mWindowOrganizerController.getTaskFragment(fragmentToken);
 
         assertNotNull(taskFragment);
@@ -1060,9 +1009,7 @@
      * its parent bounds.
      */
     @Test
-    public void testUntrustedEmbedding_configChange() throws RemoteException  {
-        mController.registerOrganizer(mIOrganizer);
-        mOrganizer.applyTransaction(mTransaction);
+    public void testUntrustedEmbedding_configChange() {
         mTaskFragment.setTaskFragmentOrganizer(mOrganizerToken, 10 /* uid */,
                 "Test:TaskFragmentOrganizer" /* processName */);
         doReturn(false).when(mTaskFragment).isAllowedToBeEmbeddedInTrustedMode();
@@ -1123,8 +1070,6 @@
         // Make minWidth/minHeight exceeds the TaskFragment bounds.
         activity.info.windowLayout = new ActivityInfo.WindowLayout(
                 0, 0, 0, 0, 0, mTaskFragBounds.width() + 10, mTaskFragBounds.height() + 10);
-        mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .setFragmentToken(mFragmentToken)
@@ -1137,7 +1082,7 @@
         // minimum dimensions.
         mTransaction.reparentActivityToTaskFragment(mFragmentToken, activity.token)
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
         // The pending event will be dispatched on the handler (from requestTraversal).
         waitHandlerIdle(mWm.mAnimationHandler);
 
@@ -1148,8 +1093,6 @@
     @Test
     public void testMinDimensionViolation_ReparentChildren() {
         final Task task = createTask(mDisplayContent);
-        mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
         final IBinder oldFragToken = new Binder();
         final TaskFragment oldTaskFrag = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
@@ -1175,7 +1118,7 @@
         mTransaction.reparentChildren(oldTaskFrag.mRemoteToken.toWindowContainerToken(),
                         mTaskFragment.mRemoteToken.toWindowContainerToken())
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
         // The pending event will be dispatched on the handler (from requestTraversal).
         waitHandlerIdle(mWm.mAnimationHandler);
 
@@ -1186,8 +1129,6 @@
     @Test
     public void testMinDimensionViolation_SetBounds() {
         final Task task = createTask(mDisplayContent);
-        mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setParentTask(task)
                 .createActivityCount(1)
@@ -1206,7 +1147,7 @@
         // minimum dimensions.
         mTransaction.setBounds(mTaskFragment.mRemoteToken.toWindowContainerToken(), mTaskFragBounds)
                 .setErrorCallbackToken(mErrorToken);
-        mWindowOrganizerController.applyTransaction(mTransaction);
+        assertApplyTransactionAllowed(mTransaction);
 
         assertWithMessage("setBounds must not be performed.")
                 .that(mTaskFragment.getBounds()).isEqualTo(task.getBounds());
@@ -1214,18 +1155,17 @@
 
     @Test
     public void testOnTransactionReady_invokeOnTransactionHandled() {
-        mController.registerOrganizer(mIOrganizer);
         final TaskFragmentTransaction transaction = new TaskFragmentTransaction();
         mOrganizer.onTransactionReady(transaction);
 
         // Organizer should always trigger #onTransactionHandled when receives #onTransactionReady
-        verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any());
-        verify(mOrganizer, never()).applyTransaction(any());
+        verify(mOrganizer).onTransactionHandled(eq(transaction.getTransactionToken()), any(),
+                anyInt(), anyBoolean());
+        verify(mOrganizer, never()).applyTransaction(any(), anyInt(), anyBoolean());
     }
 
     @Test
     public void testDispatchTransaction_deferTransitionReady() {
-        mController.registerOrganizer(mIOrganizer);
         setupMockParent(mTaskFragment, mTask);
         final ArgumentCaptor<IBinder> tokenCaptor = ArgumentCaptor.forClass(IBinder.class);
         final ArgumentCaptor<WindowContainerTransaction> wctCaptor =
@@ -1238,12 +1178,15 @@
 
         // Defer transition when send TaskFragment transaction during transition collection.
         verify(mTransitionController).deferTransitionReady();
-        verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture());
+        verify(mOrganizer).onTransactionHandled(tokenCaptor.capture(), wctCaptor.capture(),
+                anyInt(), anyBoolean());
 
-        mController.onTransactionHandled(mIOrganizer, tokenCaptor.getValue(), wctCaptor.getValue());
+        final IBinder transactionToken = tokenCaptor.getValue();
+        final WindowContainerTransaction wct = wctCaptor.getValue();
+        wct.setTaskFragmentOrganizer(mIOrganizer);
+        mController.onTransactionHandled(transactionToken, wct, getTransitionType(wct),
+                false /* shouldApplyIndependently */);
 
-        // Apply the organizer change and continue transition.
-        verify(mWindowOrganizerController).applyTransaction(wctCaptor.getValue());
         verify(mTransitionController).continueTransitionReady();
     }
 
@@ -1258,7 +1201,7 @@
         ownerActivity.getTask().effectiveUid = uid;
         final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
                 mOrganizerToken, fragmentToken, ownerActivity.token).build();
-        mOrganizer.applyTransaction(wct);
+        wct.setTaskFragmentOrganizer(mIOrganizer);
 
         // Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
         wct.createTaskFragment(params);
@@ -1266,22 +1209,14 @@
 
     /** Asserts that applying the given transaction will throw a {@link SecurityException}. */
     private void assertApplyTransactionDisallowed(WindowContainerTransaction t) {
-        assertThrows(SecurityException.class, () -> {
-            try {
-                mAtm.getWindowOrganizerController().applyTransaction(t);
-            } catch (RemoteException e) {
-                fail();
-            }
-        });
+        assertThrows(SecurityException.class, () ->
+                mController.applyTransaction(t, getTransitionType(t),
+                        false /* shouldApplyIndependently */));
     }
 
     /** Asserts that applying the given transaction will not throw any exception. */
     private void assertApplyTransactionAllowed(WindowContainerTransaction t) {
-        try {
-            mAtm.getWindowOrganizerController().applyTransaction(t);
-        } catch (RemoteException e) {
-            fail();
-        }
+        mController.applyTransaction(t, getTransitionType(t), false /* shouldApplyIndependently */);
     }
 
     /** Asserts that there will be a transaction for TaskFragment appeared. */
@@ -1367,8 +1302,6 @@
 
     /** Setups an embedded TaskFragment in a PIP Task. */
     private void setupTaskFragmentInPip() {
-        mOrganizer.applyTransaction(mTransaction);
-        mController.registerOrganizer(mIOrganizer);
         mTaskFragment = new TaskFragmentBuilder(mAtm)
                 .setCreateParentTask()
                 .setFragmentToken(mFragmentToken)
@@ -1376,8 +1309,7 @@
                 .createActivityCount(1)
                 .build();
         mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
-        mAtm.mWindowOrganizerController.mLaunchTaskFragments
-                .put(mFragmentToken, mTaskFragment);
+        mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
         mTaskFragment.getTask().setWindowingMode(WINDOWING_MODE_PINNED);
     }
 
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 6a7e388..8e89d6f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -36,7 +36,6 @@
 import static android.view.Surface.ROTATION_90;
 import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
@@ -264,7 +263,8 @@
         // Detach from process so the activities can be removed from hierarchy when finishing.
         activity1.detachFromProcess();
         activity2.detachFromProcess();
-        assertTrue(task.performClearTop(activity1, 0 /* launchFlags */).finishing);
+        int[] finishCount = new int[1];
+        assertTrue(task.performClearTop(activity1, 0 /* launchFlags */, finishCount).finishing);
         assertFalse(task.hasChild());
         // In real case, the task should be preserved for adding new activity.
         assertTrue(task.isAttached());
@@ -278,7 +278,7 @@
         doReturn(true).when(activityB).shouldBeVisibleUnchecked();
         doReturn(true).when(activityC).shouldBeVisibleUnchecked();
         activityA.getConfiguration().densityDpi += 100;
-        assertTrue(task.performClearTop(activityA, 0 /* launchFlags */).finishing);
+        assertTrue(task.performClearTop(activityA, 0 /* launchFlags */, finishCount).finishing);
         // The bottom activity should destroy directly without relaunch for config change.
         assertEquals(ActivityRecord.State.DESTROYING, activityA.getState());
         verify(activityA, never()).startRelaunching();
@@ -692,12 +692,9 @@
         // Setup the display with a top stable inset. The later assertion will ensure the inset is
         // excluded from screenHeightDp.
         final int statusBarHeight = 100;
-        final DisplayPolicy policy = display.getDisplayPolicy();
-        doAnswer(invocationOnMock -> {
-            final Rect insets = invocationOnMock.<Rect>getArgument(0);
-            insets.top = statusBarHeight;
-            return null;
-        }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
+        final DisplayInfo di = display.getDisplayInfo();
+        display.getDisplayPolicy().getDecorInsetsInfo(di.rotation,
+                di.logicalWidth, di.logicalHeight).mConfigInsets.top = statusBarHeight;
 
         // Without limiting to be inside the parent bounds, the out screen size should keep relative
         // to the input bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
index f5304d0..aa3ca18 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestDisplayContent.java
@@ -18,13 +18,6 @@
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
-import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
-import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.ITYPE_RIGHT_DISPLAY_CUTOUT;
-import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_DISPLAY_CUTOUT;
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
@@ -33,7 +26,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
 import android.annotation.Nullable;
@@ -47,7 +39,6 @@
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
-import android.view.WindowInsets;
 
 import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
 
@@ -209,26 +200,6 @@
                 doReturn(true).when(newDisplay).supportsSystemDecorations();
                 doReturn(true).when(displayPolicy).hasNavigationBar();
                 doReturn(NAV_BAR_BOTTOM).when(displayPolicy).navigationBarPosition(anyInt());
-                doReturn(Insets.of(0, 0, 0, 20)).when(displayPolicy).getInsets(any(),
-                        eq(WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars()));
-                doReturn(Insets.of(0, 20, 0, 20)).when(displayPolicy).getInsets(any(),
-                        eq(WindowInsets.Type.displayCutout() | WindowInsets.Type.navigationBars()
-                                | WindowInsets.Type.statusBars()));
-                final int[] nonDecorTypes = new int[]{
-                        ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT,
-                        ITYPE_BOTTOM_DISPLAY_CUTOUT, ITYPE_LEFT_DISPLAY_CUTOUT, ITYPE_NAVIGATION_BAR
-                };
-                doReturn(Insets.of(0, 0, 0, 20)).when(displayPolicy).getInsetsWithInternalTypes(
-                        any(),
-                        eq(nonDecorTypes));
-                final int[] stableTypes = new int[]{
-                        ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT,
-                        ITYPE_BOTTOM_DISPLAY_CUTOUT, ITYPE_LEFT_DISPLAY_CUTOUT,
-                        ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR, ITYPE_CLIMATE_BAR
-                };
-                doReturn(Insets.of(0, 20, 0, 20)).when(displayPolicy).getInsetsWithInternalTypes(
-                        any(),
-                        eq(stableTypes));
             } else {
                 doReturn(false).when(displayPolicy).hasNavigationBar();
                 doReturn(false).when(displayPolicy).hasStatusBar();
@@ -241,11 +212,6 @@
             displayPolicy.finishScreenTurningOn();
             if (mStatusBarHeight > 0) {
                 doReturn(true).when(displayPolicy).hasStatusBar();
-                doAnswer(invocation -> {
-                    Rect inOutInsets = (Rect) invocation.getArgument(0);
-                    inOutInsets.top = mStatusBarHeight;
-                    return null;
-                }).when(displayPolicy).convertNonDecorInsetsToStableInsets(any(), anyInt());
             }
             Configuration c = new Configuration();
             newDisplay.computeScreenConfiguration(c);
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 003614a..048cd7c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -27,6 +27,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -83,6 +84,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Function;
@@ -965,8 +967,17 @@
     @Test
     public void testTransientLaunch() {
         final TaskSnapshotController snapshotController = mock(TaskSnapshotController.class);
+        final ArrayList<ActivityRecord> enteringAnimReports = new ArrayList<>();
         final TransitionController controller = new TransitionController(mAtm, snapshotController,
-                mock(TransitionTracer.class));
+                mock(TransitionTracer.class)) {
+            @Override
+            protected void dispatchLegacyAppTransitionFinished(ActivityRecord ar) {
+                if (ar.mEnteringAnimation) {
+                    enteringAnimReports.add(ar);
+                }
+                super.dispatchLegacyAppTransitionFinished(ar);
+            }
+        };
         final ITransitionPlayer player = new ITransitionPlayer.Default();
         controller.registerTransitionPlayer(player, null /* playerProc */);
         final Transition openTransition = controller.createTransition(TRANSIT_OPEN);
@@ -1011,6 +1022,7 @@
 
         activity1.mVisibleRequested = false;
         activity2.mVisibleRequested = true;
+        activity2.setVisible(true);
 
         // Using abort to force-finish the sync (since we obviously can't wait for drawing).
         // We didn't call abort on the actual transition, so it will still run onTransactionReady
@@ -1021,9 +1033,11 @@
         // called until finish).
         verify(snapshotController, times(0)).recordTaskSnapshot(eq(task1), eq(false));
 
+        enteringAnimReports.clear();
         closeTransition.finishTransition();
 
         verify(snapshotController, times(1)).recordTaskSnapshot(eq(task1), eq(false));
+        assertTrue(enteringAnimReports.contains(activity2));
     }
 
     @Test
@@ -1170,6 +1184,42 @@
         assertTrue(mSyncEngine.isReady(transition.getSyncId()));
     }
 
+    @Test
+    public void testVisibleChange_snapshot() {
+        registerTestTransitionPlayer();
+        final ActivityRecord app = createActivityRecord(mDisplayContent);
+        final Transition transition = new Transition(TRANSIT_CHANGE, 0 /* flags */,
+                app.mTransitionController, mWm.mSyncEngine);
+        app.mTransitionController.moveToCollecting(transition, BLASTSyncEngine.METHOD_NONE);
+        final SurfaceControl mockSnapshot = mock(SurfaceControl.class);
+        transition.setContainerFreezer(new Transition.IContainerFreezer() {
+            @Override
+            public boolean freeze(@NonNull WindowContainer wc, @NonNull Rect bounds) {
+                Objects.requireNonNull(transition.mChanges.get(wc)).mSnapshot = mockSnapshot;
+                return true;
+            }
+
+            @Override
+            public void cleanUp(SurfaceControl.Transaction t) {
+            }
+        });
+        final Task task = app.getTask();
+        transition.collect(task);
+        final Rect bounds = new Rect(task.getBounds());
+        Configuration c = new Configuration(task.getRequestedOverrideConfiguration());
+        bounds.inset(10, 10);
+        c.windowConfiguration.setBounds(bounds);
+        task.onRequestedOverrideConfigurationChanged(c);
+
+        ArrayList<WindowContainer> targets = Transition.calculateTargets(
+                transition.mParticipants, transition.mChanges);
+        TransitionInfo info = Transition.calculateTransitionInfo(
+                TRANSIT_CHANGE, 0, targets, transition.mChanges, mMockT);
+        assertEquals(mockSnapshot,
+                info.getChange(task.mRemoteToken.toWindowContainerToken()).getSnapshot());
+        transition.abort();
+    }
+
     private static void makeTaskOrganized(Task... tasks) {
         final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
         for (Task t : tasks) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index fba4ff1..6333508 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -33,21 +33,26 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.InsetsState;
@@ -59,11 +64,12 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.server.wm.utils.WmDisplayCutout;
-
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 /**
  * Tests for the {@link WallpaperController} class.
  *
@@ -74,6 +80,18 @@
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class WallpaperControllerTests extends WindowTestsBase {
+    private static final int INITIAL_WIDTH = 600;
+    private static final int INITIAL_HEIGHT = 900;
+    private static final int SECOND_WIDTH = 300;
+
+    @Before
+    public void setup() {
+        Resources resources = mWm.mContext.getResources();
+        spyOn(resources);
+        doReturn(false).when(resources).getBoolean(
+                com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay);
+    }
+
     @Test
     public void testWallpaperScreenshot() {
         WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class);
@@ -145,8 +163,8 @@
         // Apply the fixed transform
         Configuration config = new Configuration();
         final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
-        final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
-        final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), new InsetsState(),
+        final DisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
+        final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(),
                 info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
         wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config);
 
@@ -365,6 +383,108 @@
         assertTrue(token.isVisible());
     }
 
+    private static void prepareSmallerSecondDisplay(DisplayContent dc, int width, int height) {
+        spyOn(dc.mWmService);
+        DisplayInfo firstDisplay = dc.getDisplayInfo();
+        DisplayInfo secondDisplay = new DisplayInfo(firstDisplay);
+        // Second display is narrower than first display.
+        secondDisplay.logicalWidth = width;
+        secondDisplay.logicalHeight = height;
+        doReturn(List.of(firstDisplay, secondDisplay)).when(
+                dc.mWmService).getPossibleDisplayInfoLocked(anyInt());
+    }
+
+    private static void resizeDisplayAndWallpaper(DisplayContent dc, WindowState wallpaperWindow,
+            int width, int height) {
+        dc.setBounds(0, 0, width, height);
+        dc.updateOrientation();
+        dc.sendNewConfiguration();
+        spyOn(wallpaperWindow);
+        doReturn(new Rect(0, 0, width, height)).when(wallpaperWindow).getLastReportedBounds();
+    }
+
+    @Test
+    public void testUpdateWallpaperOffset_initial_shouldCenterDisabled() {
+        final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH,
+                INITIAL_HEIGHT).build();
+        dc.mWallpaperController.setShouldOffsetWallpaperCenter(false);
+        prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT);
+        final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH,
+                INITIAL_HEIGHT);
+
+        dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false);
+
+        // Wallpaper centering is disabled, so no offset.
+        assertThat(wallpaperWindow.mXOffset).isEqualTo(0);
+        assertThat(wallpaperWindow.mYOffset).isEqualTo(0);
+    }
+
+    @Test
+    public void testUpdateWallpaperOffset_initial_shouldCenterEnabled() {
+        final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH,
+                INITIAL_HEIGHT).build();
+        dc.mWallpaperController.setShouldOffsetWallpaperCenter(true);
+        prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT);
+        final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH,
+                INITIAL_HEIGHT);
+
+        dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false);
+
+        // Wallpaper matches first display, so has no offset.
+        assertThat(wallpaperWindow.mXOffset).isEqualTo(0);
+        assertThat(wallpaperWindow.mYOffset).isEqualTo(0);
+    }
+
+    @Test
+    public void testUpdateWallpaperOffset_resize_shouldCenterEnabled() {
+        final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH,
+                INITIAL_HEIGHT).build();
+        dc.mWallpaperController.setShouldOffsetWallpaperCenter(true);
+        prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT);
+        final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH,
+                INITIAL_HEIGHT);
+
+        dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false);
+
+        // Resize display to match second display bounds.
+        resizeDisplayAndWallpaper(dc, wallpaperWindow, SECOND_WIDTH, INITIAL_HEIGHT);
+
+        dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false);
+
+        // Wallpaper is 300 wider than second display.
+        assertThat(wallpaperWindow.mXOffset).isEqualTo(-Math.abs(INITIAL_WIDTH - SECOND_WIDTH) / 2);
+        assertThat(wallpaperWindow.mYOffset).isEqualTo(0);
+    }
+
+    @Test
+    public void testUpdateWallpaperOffset_resize_shouldCenterDisabled() {
+        final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH,
+                INITIAL_HEIGHT).build();
+        dc.mWallpaperController.setShouldOffsetWallpaperCenter(false);
+        prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT);
+        final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH,
+                INITIAL_HEIGHT);
+
+        dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false);
+
+        // Resize display to match second display bounds.
+        resizeDisplayAndWallpaper(dc, wallpaperWindow, SECOND_WIDTH, INITIAL_HEIGHT);
+
+        dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false);
+
+        // Wallpaper is 300 wider than second display, but offset disabled.
+        assertThat(wallpaperWindow.mXOffset).isEqualTo(0);
+        assertThat(wallpaperWindow.mYOffset).isEqualTo(0);
+    }
+
+    private WindowState createWallpaperWindow(DisplayContent dc, int width, int height) {
+        final WindowState wallpaperWindow = createWallpaperWindow(dc);
+        // Wallpaper is cropped to match first display.
+        wallpaperWindow.getWindowFrames().mParentFrame.set(new Rect(0, 0, width, height));
+        wallpaperWindow.getWindowFrames().mFrame.set(0, 0, width, height);
+        return wallpaperWindow;
+    }
+
     private WindowState createWallpaperWindow(DisplayContent dc) {
         final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
                 true /* explicit */, dc, true /* ownerCanManageAppTokens */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
new file mode 100644
index 0000000..d255271
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.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.wm;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeast;
+
+import android.content.Intent;
+import android.platform.test.annotations.Presubmit;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+
+import androidx.annotation.NonNull;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link WindowContainerTransaction}.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:WindowContainerTransactionTests
+ */
+@SmallTest
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class WindowContainerTransactionTests extends WindowTestsBase {
+
+    @Test
+    public void testRemoveTask() {
+        final Task rootTask = createTask(mDisplayContent);
+        final Task task = createTaskInRootTask(rootTask, 0 /* userId */);
+        final ActivityRecord activity = createActivityRecord(mDisplayContent, task);
+
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        WindowContainerToken token = task.getTaskInfo().token;
+        wct.removeTask(token);
+        applyTransaction(wct);
+
+        // There is still an activity to be destroyed, so the task is not removed immediately.
+        assertNotNull(task.getParent());
+        assertTrue(rootTask.hasChild());
+        assertTrue(task.hasChild());
+        assertTrue(activity.finishing);
+
+        activity.destroyed("testRemoveContainer");
+        // Assert that the container was removed after the activity is destroyed.
+        assertNull(task.getParent());
+        assertEquals(0, task.getChildCount());
+        assertNull(activity.getParent());
+        verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(task);
+        verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask);
+    }
+
+    private Task createTask(int taskId) {
+        return new Task.Builder(mAtm)
+                .setTaskId(taskId)
+                .setIntent(new Intent())
+                .setRealActivity(ActivityBuilder.getDefaultComponent())
+                .setEffectiveUid(10050)
+                .buildInner();
+    }
+
+    private void applyTransaction(@NonNull WindowContainerTransaction t) {
+        if (!t.isEmpty()) {
+            mWm.mAtmService.mWindowOrganizerController.applyTransaction(t);
+        }
+    }
+}
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 6785979..353b757 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -26,6 +26,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.os.Process.SYSTEM_UID;
+import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.View.VISIBLE;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
@@ -69,6 +70,7 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayManager;
@@ -84,6 +86,7 @@
 import android.view.Gravity;
 import android.view.IDisplayWindowInsetsController;
 import android.view.IWindow;
+import android.view.InsetsFrameProvider;
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.InsetsVisibilities;
@@ -419,6 +422,15 @@
                 true /* ownerCanManageAppTokens */);
     }
 
+    WindowState createNavBarWithProvidedInsets(DisplayContent dc) {
+        final WindowState navbar = createWindow(null, TYPE_NAVIGATION_BAR, dc, "navbar");
+        navbar.mAttrs.providedInsets = new InsetsFrameProvider[] {
+                new InsetsFrameProvider(ITYPE_NAVIGATION_BAR, Insets.of(0, 0, 0, NAV_BAR_HEIGHT))
+        };
+        dc.getDisplayPolicy().addWindowLw(navbar, navbar.mAttrs);
+        return navbar;
+    }
+
     WindowState createAppWindow(Task task, int type, String name) {
         final ActivityRecord activity = createNonAttachedActivityRecord(task.getDisplayContent());
         task.addChild(activity, 0);
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index f169926..1b34b81 100644
--- a/services/usage/java/com/android/server/usage/AppTimeLimitController.java
+++ b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
@@ -772,7 +772,7 @@
             observerApp.appUsageGroups.append(observerId, group);
 
             if (DEBUG) {
-                Slog.d(TAG, "addObserver " + observed + " for " + timeLimit);
+                Slog.d(TAG, "addObserver " + Arrays.toString(observed) + " for " + timeLimit);
             }
 
             user.addUsageGroup(group);
@@ -881,7 +881,7 @@
             observerApp.appUsageLimitGroups.append(observerId, group);
 
             if (DEBUG) {
-                Slog.d(TAG, "addObserver " + observed + " for " + timeLimit);
+                Slog.d(TAG, "addObserver " + Arrays.toString(observed) + " for " + timeLimit);
             }
 
             user.addUsageGroup(group);
diff --git a/services/usb/java/com/android/server/usb/PowerBoostSetter.java b/services/usb/java/com/android/server/usb/PowerBoostSetter.java
new file mode 100644
index 0000000..eb7c196
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/PowerBoostSetter.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.usb;
+
+import android.os.PowerManagerInternal;
+import android.util.Log;
+
+import com.android.server.LocalServices;
+
+import java.time.Instant;
+
+/**
+ * Sends power boost events to the power manager.
+ */
+public class PowerBoostSetter {
+    private static final String TAG = "PowerBoostSetter";
+    // Set power boost timeout to 15 seconds
+    private static final int POWER_BOOST_TIMEOUT_MS = 15 * 1000;
+
+    PowerManagerInternal mPowerManagerInternal = null;
+    Instant mPreviousTimeout = null;
+
+    PowerBoostSetter() {
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+    }
+
+    /**
+     * Boosts the CPU clock frequency as if the screen is touched
+     */
+    public void boostPower() {
+        if (mPowerManagerInternal == null) {
+            mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
+        }
+
+        if (mPowerManagerInternal == null) {
+            Log.w(TAG, "PowerManagerInternal null");
+        } else if ((mPreviousTimeout == null) || Instant.now().isAfter(
+                mPreviousTimeout.plusMillis(POWER_BOOST_TIMEOUT_MS / 2))) {
+            // Only boost if the previous timeout is at least halfway done
+            mPreviousTimeout = Instant.now();
+            mPowerManagerInternal.setPowerBoost(PowerManagerInternal.BOOST_INTERACTION,
+                    POWER_BOOST_TIMEOUT_MS);
+        }
+    }
+}
diff --git a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
index eebcccb..2ae328b 100644
--- a/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbDirectMidiDevice.java
@@ -98,6 +98,11 @@
 
     private UsbMidiPacketConverter mUsbMidiPacketConverter;
 
+    private PowerBoostSetter mPowerBoostSetter = null;
+
+    private static final byte MESSAGE_TYPE_MIDI_1_CHANNEL_VOICE = 0x02;
+    private static final byte MESSAGE_TYPE_MIDI_2_CHANNEL_VOICE = 0x04;
+
     private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() {
         @Override
         public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
@@ -251,6 +256,8 @@
         for (int port = 0; port < numOutputs; port++) {
             mMidiInputPortReceivers[port] = new InputReceiverProxy();
         }
+
+        mPowerBoostSetter = new PowerBoostSetter();
     }
 
     private int calculateDefaultMidiProtocol() {
@@ -418,6 +425,15 @@
                                     }
                                     outputReceivers[portFinal].send(convertedArray, 0,
                                             convertedArray.length, timestamp);
+
+                                    // Boost power if there seems to be a voice message.
+                                    // For legacy devices, boost when message is more than size 1.
+                                    // For UMP devices, boost for channel voice messages.
+                                    if ((mPowerBoostSetter != null && convertedArray.length > 1)
+                                            && (!mIsUniversalMidiDevice
+                                            || isChannelVoiceMessage(convertedArray))) {
+                                        mPowerBoostSetter.boostPower();
+                                    }
                                 }
                             }
                         } catch (IOException e) {
@@ -721,4 +737,10 @@
 
         dump.end(token);
     }
+
+    private boolean isChannelVoiceMessage(byte[] umpMessage) {
+        byte messageType = (byte) ((umpMessage[0] >> 4) & 0x0f);
+        return messageType == MESSAGE_TYPE_MIDI_1_CHANNEL_VOICE
+                || messageType == MESSAGE_TYPE_MIDI_2_CHANNEL_VOICE;
+    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 67955e15..d9ad703 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -77,6 +77,8 @@
     // only accessed from JNI code
     private int mPipeFD = -1;
 
+    private PowerBoostSetter mPowerBoostSetter = null;
+
     private final MidiDeviceServer.Callback mCallback = new MidiDeviceServer.Callback() {
         @Override
         public void onDeviceStatusChanged(MidiDeviceServer server, MidiDeviceStatus status) {
@@ -167,6 +169,8 @@
         for (int port = 0; port < numOutputs; port++) {
             mMidiInputPortReceivers[port] = new InputReceiverProxy();
         }
+
+        mPowerBoostSetter = new PowerBoostSetter();
     }
 
     private boolean openLocked() {
@@ -240,6 +244,11 @@
 
                                         int count = mInputStreams[index].read(buffer);
                                         outputReceivers[index].send(buffer, 0, count, timestamp);
+
+                                        // If messages are more than size 1, boost power.
+                                        if (mPowerBoostSetter != null && count > 1) {
+                                            mPowerBoostSetter.boostPower();
+                                        }
                                     }
                                 }
                             }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 63781cc..980b3b5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -618,10 +618,10 @@
 
         mScheduledExecutorService.execute(() -> {
             if (DEBUG) {
-                Slog.d(TAG, "call updateVisibleActivitiesLocked from enable listening");
+                Slog.d(TAG, "call handleVisibleActivitiesLocked from enable listening");
             }
             synchronized (mLock) {
-                updateVisibleActivitiesLocked();
+                handleVisibleActivitiesLocked();
             }
         });
     }
@@ -646,10 +646,10 @@
         }
         mScheduledExecutorService.execute(() -> {
             if (DEBUG) {
-                Slog.d(TAG, "call updateVisibleActivitiesLocked from activity event");
+                Slog.d(TAG, "call handleVisibleActivitiesLocked from activity event");
             }
             synchronized (mLock) {
-                updateVisibleActivitiesLocked();
+                handleVisibleActivitiesLocked();
             }
         });
     }
@@ -684,9 +684,9 @@
         return visibleActivityInfos;
     }
 
-    private void updateVisibleActivitiesLocked() {
+    private void handleVisibleActivitiesLocked() {
         if (DEBUG) {
-            Slog.d(TAG, "updateVisibleActivitiesLocked");
+            Slog.d(TAG, "handleVisibleActivitiesLocked");
         }
         if (mSession == null) {
             return;
@@ -697,13 +697,13 @@
         final List<VisibleActivityInfo> newVisibleActivityInfos = getVisibleActivityInfosLocked();
 
         if (newVisibleActivityInfos == null || newVisibleActivityInfos.isEmpty()) {
-            updateVisibleActivitiesChangedLocked(mVisibleActivityInfos,
+            notifyVisibleActivitiesChangedLocked(mVisibleActivityInfos,
                     VisibleActivityInfo.TYPE_ACTIVITY_REMOVED);
             mVisibleActivityInfos.clear();
             return;
         }
         if (mVisibleActivityInfos.isEmpty()) {
-            updateVisibleActivitiesChangedLocked(newVisibleActivityInfos,
+            notifyVisibleActivitiesChangedLocked(newVisibleActivityInfos,
                     VisibleActivityInfo.TYPE_ACTIVITY_ADDED);
             mVisibleActivityInfos.addAll(newVisibleActivityInfos);
             return;
@@ -724,11 +724,11 @@
         }
 
         if (!addedActivities.isEmpty()) {
-            updateVisibleActivitiesChangedLocked(addedActivities,
+            notifyVisibleActivitiesChangedLocked(addedActivities,
                     VisibleActivityInfo.TYPE_ACTIVITY_ADDED);
         }
         if (!removedActivities.isEmpty()) {
-            updateVisibleActivitiesChangedLocked(removedActivities,
+            notifyVisibleActivitiesChangedLocked(removedActivities,
                     VisibleActivityInfo.TYPE_ACTIVITY_REMOVED);
         }
 
@@ -736,7 +736,7 @@
         mVisibleActivityInfos.addAll(newVisibleActivityInfos);
     }
 
-    private void updateVisibleActivitiesChangedLocked(
+    private void notifyVisibleActivitiesChangedLocked(
             List<VisibleActivityInfo> visibleActivityInfos, int type) {
         if (visibleActivityInfos == null || visibleActivityInfos.isEmpty()) {
             return;
@@ -746,15 +746,15 @@
         }
         try {
             for (int i = 0; i < visibleActivityInfos.size(); i++) {
-                mSession.updateVisibleActivityInfo(visibleActivityInfos.get(i), type);
+                mSession.notifyVisibleActivityInfoChanged(visibleActivityInfos.get(i), type);
             }
         } catch (RemoteException e) {
             if (DEBUG) {
-                Slog.w(TAG, "updateVisibleActivitiesChangedLocked RemoteException : " + e);
+                Slog.w(TAG, "notifyVisibleActivitiesChangedLocked RemoteException : " + e);
             }
         }
         if (DEBUG) {
-            Slog.d(TAG, "updateVisibleActivitiesChangedLocked type=" + type + ", count="
+            Slog.d(TAG, "notifyVisibleActivitiesChangedLocked type=" + type + ", count="
                     + visibleActivityInfos.size());
         }
     }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 49ad585..7c736e3 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2763,6 +2763,12 @@
      * @param isVoip True if the audio mode is VOIP.
      */
     public final void setAudioModeIsVoip(boolean isVoip) {
+        if (!isVoip && (mConnectionProperties & PROPERTY_SELF_MANAGED) == PROPERTY_SELF_MANAGED) {
+            Log.i(this,
+                    "setAudioModeIsVoip: Ignored request to set a self-managed connection's"
+                            + " audioModeIsVoip to false. Doing so can cause unwanted behavior.");
+            return;
+        }
         checkImmutable();
         mAudioModeIsVoip = isVoip;
         for (Listener l : mListeners) {
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 0f034ad..b003f59 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -88,8 +88,8 @@
     public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
 
     /**
-     * Reason code (returned via {@link #getReason()}), which indicates that the video telephony
-     * call was disconnected because IMS access is blocked.
+     * Reason code (returned via {@link #getReason()}), which indicates that the call was
+     * disconnected because IMS access is blocked.
      */
     public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 9fcf44e..ccec67e 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -15,6 +15,7 @@
 package android.telecom;
 
 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.content.Intent.LOCAL_FLAG_FROM_SYSTEM;
 
 import android.Manifest;
 import android.annotation.IntDef;
@@ -2417,6 +2418,10 @@
         if (service != null) {
             try {
                 result = service.createManageBlockedNumbersIntent(mContext.getPackageName());
+                if (result != null) {
+                    result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+                            mContext.getAttributionSource());
+                }
             } catch (RemoteException e) {
                 Log.e(TAG, "Error calling ITelecomService#createManageBlockedNumbersIntent", e);
             }
@@ -2438,7 +2443,12 @@
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
-                return service.createLaunchEmergencyDialerIntent(number);
+                Intent result = service.createLaunchEmergencyDialerIntent(number);
+                if (result != null) {
+                    result.prepareToEnterProcess(LOCAL_FLAG_FROM_SYSTEM,
+                            mContext.getAttributionSource());
+                }
+                return result;
             } catch (RemoteException e) {
                 Log.e(TAG, "Error createLaunchEmergencyDialerIntent", e);
             }
diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java
index 677fe2f..62eac7a 100755
--- a/telephony/common/com/google/android/mms/pdu/PduParser.java
+++ b/telephony/common/com/google/android/mms/pdu/PduParser.java
@@ -793,7 +793,7 @@
                         try {
                             if (LOCAL_LOGV) {
                                 Log.v(LOG_TAG, "parseHeaders: CONTENT_TYPE: " + headerField +
-                                        contentType.toString());
+                                        Arrays.toString(contentType));
                             }
                             headers.setTextString(contentType, PduHeaders.CONTENT_TYPE);
                         } catch(NullPointerException e) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4af8cde..3023ec9 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -579,11 +579,21 @@
      * List of network type constants which support only a single data connection at a time.
      * Some carriers do not support multiple PDP on UMTS.
      * @see TelephonyManager NETWORK_TYPE_*
+     * @see #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY
      */
     public static final String
             KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array";
 
     /**
+     * Only apply if {@link #KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY} specifies the network types that
+     * support a single data connection at a time. This key defines a list of network capabilities
+     * which, if requested, will exempt the request from single data connection checks.
+     * @see NetworkCapabilities NET_CAPABILITY_*
+     */
+    public static final String KEY_CAPABILITIES_EXEMPT_FROM_SINGLE_DC_CHECK_INT_ARRAY =
+            "capabilities_exempt_from_single_dc_check_int_array";
+
+    /**
      * Override the platform's notion of a network operator being considered roaming.
      * Value is string array of MCCMNCs to be considered roaming for 3GPP RATs.
      */
@@ -8887,6 +8897,8 @@
                 new int[] {TelephonyManager.NETWORK_TYPE_CDMA, TelephonyManager.NETWORK_TYPE_1xRTT,
                         TelephonyManager.NETWORK_TYPE_EVDO_0, TelephonyManager.NETWORK_TYPE_EVDO_A,
                         TelephonyManager.NETWORK_TYPE_EVDO_B});
+        sDefaults.putIntArray(KEY_CAPABILITIES_EXEMPT_FROM_SINGLE_DC_CHECK_INT_ARRAY,
+                new int[] {NetworkCapabilities.NET_CAPABILITY_IMS});
         sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
         sDefaults.putString(KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index e882b25..23835a7 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -987,8 +987,15 @@
     /** The ePDG does not support un-authenticated IMSI based emergency PDN bringup **/
     public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 0x2B2F;
 
-    // Device is unable to establish an IPSec tunnel with the ePDG for any reason
-    // e.g authentication fail or certificate validation or DNS Resolution and timeout failure.
+    // The below error causes are relevant when the device is unable to establish an IPSec tunnel
+    // with the ePDG for any reason, e.g. authentication fail or certificate validation or DNS
+    // Resolution and timeout failure.
+
+    /**
+     * The requested service was rejected because of congestion in the network while accessing the
+     * IWLAN ePDG. Defined in 3GPP TS 24.502, Section 9.2.4.2.
+     */
+    public static final int IWLAN_CONGESTION = 0x3C8C;
 
     /** IKE configuration error resulting in failure  */
     public static final int IWLAN_IKEV2_CONFIG_FAILURE = 0x4000;
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index d978f57..212aaae 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -433,7 +433,8 @@
         return Objects.hash(
                 mCellConnectionStatus, mCellBandwidthDownlinkKhz, mCellBandwidthUplinkKhz,
                 mNetworkType, mFrequencyRange, mDownlinkChannelNumber, mUplinkChannelNumber,
-                mContextIds, mPhysicalCellId, mBand, mDownlinkFrequency, mUplinkFrequency);
+                Arrays.hashCode(mContextIds), mPhysicalCellId, mBand, mDownlinkFrequency,
+                mUplinkFrequency);
     }
 
     public static final
diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java
index ae7d209..3c18245 100644
--- a/telephony/java/android/telephony/SignalThresholdInfo.java
+++ b/telephony/java/android/telephony/SignalThresholdInfo.java
@@ -574,8 +574,8 @@
 
     @Override
     public int hashCode() {
-        return Objects.hash(mRan, mSignalMeasurementType, mHysteresisMs, mHysteresisDb, mThresholds,
-                mIsEnabled);
+        return Objects.hash(mRan, mSignalMeasurementType, mHysteresisMs, mHysteresisDb,
+                Arrays.hashCode(mThresholds), mIsEnabled);
     }
 
     public static final @NonNull Parcelable.Creator<SignalThresholdInfo> CREATOR =
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index cbd03c7..d670e55 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -1935,7 +1935,7 @@
                         + " at calling enableCellBroadcastRangeForSubscriber. subId = " + subId);
             }
         } catch (RemoteException ex) {
-            Rlog.d(TAG, "enableCellBroadcastRange: " + ex.getStackTrace());
+            Rlog.d(TAG, "enableCellBroadcastRange: ", ex);
             // ignore it
         }
 
@@ -1996,7 +1996,7 @@
                         + " at calling disableCellBroadcastRangeForSubscriber. subId = " + subId);
             }
         } catch (RemoteException ex) {
-            Rlog.d(TAG, "disableCellBroadcastRange: " + ex.getStackTrace());
+            Rlog.d(TAG, "disableCellBroadcastRange: ", ex);
             // ignore it
         }
 
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index c36eb2f..cb985bf 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -967,9 +967,9 @@
     public int hashCode() {
         return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
                 mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc, mCountryIso, mCardString,
-                mCardId, mDisplayName, mCarrierName, mNativeAccessRules, mIsGroupDisabled,
-                mCarrierId, mProfileClass, mGroupOwner, mAreUiccApplicationsEnabled, mPortIndex,
-                mUsageSetting);
+                mCardId, mDisplayName, mCarrierName, Arrays.hashCode(mNativeAccessRules),
+                mIsGroupDisabled, mCarrierId, mProfileClass, mGroupOwner,
+                mAreUiccApplicationsEnabled, mPortIndex, mUsageSetting);
     }
 
     @Override
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/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index e0c5298..19f2a9b 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -171,7 +171,7 @@
                                 ci[i] = (CellInfo) parcelables[i];
                             }
                             executor.execute(() -> {
-                                Rlog.d(TAG, "onResults: " + ci.toString());
+                                Rlog.d(TAG, "onResults: " + Arrays.toString(ci));
                                 callback.onResults(Arrays.asList(ci));
                             });
                         } catch (Exception e) {
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..3032bab 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.
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 3853af2..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)
         }
     }
 
@@ -164,7 +158,6 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                     .getConfigNonRotationTests(
-                            repetitions = 1,
                             supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
                             supportedNavigationModes = listOf(
                                     WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 9cc1bfe..ec2b4fa 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -95,7 +95,7 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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 58a8011..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
@@ -103,7 +101,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index f6f3f58..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)
@@ -113,8 +109,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    // b/190352379 (IME doesn't show on app launch in 90 degrees)
+                                        // b/190352379 (IME doesn't show on app launch in 90 degrees)
                     supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
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 52f561e..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()
@@ -123,7 +117,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3,
+                .getConfigNonRotationTests(
                     // b/190352379 (IME doesn't show on app launch in 90 degrees)
                     supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
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 c6e25d3..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)
         }
     }
 
@@ -141,7 +135,6 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 2,
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
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 23bd220..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)
@@ -121,7 +115,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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 8ce1840..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)
         }
     }
 
@@ -134,8 +128,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedRotations = listOf(Surface.ROTATION_0),
+                                        supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
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 a04a50f..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)
@@ -127,14 +123,13 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(
-                            repetitions = 3,
-                            supportedRotations = listOf(Surface.ROTATION_0),
-                            supportedNavigationModes = listOf(
-                                    WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                                    WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                            )
+                .getConfigNonRotationTests(
+                    supportedRotations = listOf(Surface.ROTATION_0),
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     )
+                )
         }
     }
 }
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 04e4bc9..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)
@@ -141,8 +137,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedRotations = listOf(Surface.ROTATION_0),
+                                        supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
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 b10aed3..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)
         }
     }
 
@@ -82,8 +78,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedRotations = listOf(Surface.ROTATION_0),
+                                        supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
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 d900815..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()
 
@@ -117,8 +111,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedRotations = listOf(Surface.ROTATION_90),
+                                        supportedRotations = listOf(Surface.ROTATION_90),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     )
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 fdc2193..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)
         }
     }
 
@@ -95,8 +89,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedRotations = listOf(Surface.ROTATION_0),
+                                        supportedRotations = listOf(Surface.ROTATION_0),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
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 9475734..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)
@@ -265,7 +262,6 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 1,
                     supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
                     supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
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 2e22e62..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)
         }
     }
 
@@ -192,8 +186,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedRotations = listOf(Surface.ROTATION_0)
+                                        supportedRotations = listOf(Surface.ROTATION_0)
                 )
         }
     }
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 4f47ec4..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
@@ -200,8 +194,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedNavigationModes = listOf(
+                                        supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     ),
                     supportedRotations = listOf(Surface.ROTATION_0)
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 33c280e..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)
@@ -142,7 +138,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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..354964d 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,12 @@
         get() = {
             super.transition(this)
             setup {
-                eachRun {
-                    tapl.setExpectedRotation(Surface.ROTATION_0)
-                    RemoveAllTasksButHomeRule.removeAllTasksButHome()
-                    this.setRotation(testSpec.startRotation)
-                }
+                tapl.setExpectedRotation(Surface.ROTATION_0)
+                RemoveAllTasksButHomeRule.removeAllTasksButHome()
+                this.setRotation(testSpec.startRotation)
             }
             teardown {
-                eachRun {
-                    testApp.exit(wmHelper)
-                }
+                testApp.exit(wmHelper)
             }
             transitions {
                 tapl.goHome()
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 bfc7b39..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()
             }
         }
 
@@ -171,7 +169,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(repetitions = 3)
+                    .getConfigNonRotationTests()
         }
     }
 }
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 f93d7a0..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()
             }
         }
 
@@ -221,7 +219,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(repetitions = 3)
+                    .getConfigNonRotationTests()
         }
     }
 }
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 75311ea..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)
             }
         }
 
@@ -127,7 +123,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                    .getConfigNonRotationTests(repetitions = 3)
+                    .getConfigNonRotationTests()
         }
     }
 }
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 dbe5418..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.
@@ -157,7 +69,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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 915b702..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)
             }
         }
 
@@ -284,7 +278,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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 7c07ace..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()
@@ -130,7 +126,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 53be7d4..82e30ac 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -233,8 +233,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedNavigationModes =
+                                        supportedNavigationModes =
                     listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
                     supportedRotations = listOf(Surface.ROTATION_0)
                 )
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 fe5e74b..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)
@@ -263,7 +259,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 3)
+                .getConfigNonRotationTests()
         }
     }
 }
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 181767b..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()
 
@@ -278,8 +271,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                 .getConfigNonRotationTests(
-                    repetitions = 3,
-                    supportedNavigationModes = listOf(
+                                        supportedNavigationModes = listOf(
                         WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                     ),
                     supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
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 0f05622..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
 
@@ -298,8 +279,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                     .getConfigNonRotationTests(
-                            repetitions = 3,
-                            supportedNavigationModes = listOf(
+                                                        supportedNavigationModes = listOf(
                                     WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                             ),
                             supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
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 d1f356c..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()
@@ -324,8 +303,7 @@
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
                     .getConfigNonRotationTests(
-                            repetitions = 3,
-                            supportedNavigationModes = listOf(
+                                                        supportedNavigationModes = listOf(
                                     WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
                             ),
                             // TODO: Test with 90 rotation
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 4be8963..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.
@@ -146,7 +138,7 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigRotationTests(repetitions = 3)
+                .getConfigRotationTests()
         }
     }
 }
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 0912812..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()
                     )
-                }
+                )
             }
         }
 
@@ -241,7 +239,7 @@
         @JvmStatic
         private fun getConfigurations(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigRotationTests(repetitions = 2)
+                .getConfigRotationTests()
                 .flatMap { sourceConfig ->
                     val defaultRun = createConfig(sourceConfig, starveUiThread = false)
                     val busyUiRun = createConfig(sourceConfig, starveUiThread = true)
diff --git a/tests/FlickerTests/test-apps/flickerapp/Android.bp b/tests/FlickerTests/test-apps/flickerapp/Android.bp
index 0c698ab..9b1262d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/Android.bp
+++ b/tests/FlickerTests/test-apps/flickerapp/Android.bp
@@ -27,7 +27,19 @@
     sdk_version: "current",
     test_suites: ["device-tests"],
     static_libs: [
+        "androidx.annotation_annotation",
+        "androidx.appcompat_appcompat",
+        "androidx-constraintlayout_constraintlayout",
+        "androidx.core_core",
+        "androidx.fragment_fragment",
+        "androidx.recyclerview_recyclerview",
         "androidx.test.ext.junit",
+        "androidx.navigation_navigation-common-ktx",
+        "androidx.navigation_navigation-fragment-ktx",
+        "androidx.navigation_navigation-runtime-ktx",
+        "androidx.navigation_navigation-ui-ktx",
+        "kotlin-stdlib",
+        "kotlinx-coroutines-android",
         "wm-flicker-common-app-helpers",
         "wm-flicker-window-extensions",
     ],
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 387f19b..54662ef 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -165,7 +165,6 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
-
         <activity
             android:name=".ActivityEmbeddingMainActivity"
             android:label="ActivityEmbedding Main"
@@ -193,5 +192,27 @@
             android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false"/>
+        <activity android:name=".MailActivity"
+            android:exported="true"
+            android:label="MailApp"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.MailActivity"
+            android:theme="@style/Theme.AppCompat.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <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/anim/slide_in_from_bottom.xml b/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml
new file mode 100644
index 0000000..c0165e5
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/anim/slide_in_from_bottom.xml
@@ -0,0 +1,25 @@
+<?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.
+  -->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:interpolator="@android:anim/linear_interpolator"
+    android:shareInterpolator="false">
+    <translate
+        android:duration="500"
+        android:fromYDelta="100%p"
+        android:toYDelta="0%p" />
+</set>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
new file mode 100644
index 0000000..8a97433
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
@@ -0,0 +1,34 @@
+<?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.
+  -->
+
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <fragment
+        android:id="@+id/main_fragment"
+        android:name="androidx.navigation.fragment.NavHostFragment"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:defaultNavHost="true"
+        app:layout_constraintLeft_toLeftOf="parent"
+        app:layout_constraintRight_toRightOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:navGraph="@navigation/mail_navigation"></fragment>
+</androidx.constraintlayout.widget.ConstraintLayout>
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/res/layout/fragment_mail_content.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml
new file mode 100644
index 0000000..fbbdc5b
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_content.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml
new file mode 100644
index 0000000..0e30745
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/fragment_mail_list.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/mail_recycle_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml
new file mode 100644
index 0000000..c39bfb3
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/mail_row_item.xml
@@ -0,0 +1,37 @@
+<?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.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/list_item_height"
+    android:layout_marginLeft="@dimen/margin_medium"
+    android:layout_marginRight="@dimen/margin_medium">
+    <ImageView
+        android:id="@+id/mail_row_item_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/padding_small"
+        android:paddingEnd="@dimen/padding_small"
+        android:paddingStart="@dimen/padding_small"
+        android:paddingTop="@dimen/padding_small"/>
+    <TextView
+        android:id="@+id/mail_row_item_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingEnd="@dimen/padding_small"
+        android:textSize="@dimen/list_item_text_size" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml b/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml
new file mode 100644
index 0000000..d12707a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/navigation/mail_navigation.xml
@@ -0,0 +1,36 @@
+<?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.
+  -->
+
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/mail_navigation"
+    app:startDestination="@id/fragment_mail_list">
+    <fragment
+        android:id="@+id/fragment_mail_list"
+        android:name=".MailListFragment"
+        android:label="Mail List">
+        <action
+            android:id="@+id/action_mail_list_to_mail_content"
+            app:destination="@id/fragment_mail_content"
+            app:enterAnim="@anim/slide_in_from_bottom" />
+    </fragment>
+    <fragment
+        android:id="@+id/fragment_mail_content"
+        android:name=".MailContentFragment"
+        android:label="Mail Content">
+    </fragment>
+</navigation>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml
new file mode 100644
index 0000000..0b0763d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/values/dimens.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ 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>
+    <dimen name="padding_small">8dp</dimen>
+    <dimen name="margin_medium">16dp</dimen>
+    <dimen name="list_item_height">72dp</dimen>
+    <dimen name="list_item_text_size">24dp</dimen>
+    <dimen name="icon_size">64dp</dimen>
+    <dimen name="icon_text_size">36dp</dimen>
+</resources>
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..72a02f2 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,9 @@
             ACTIVITY_EMBEDDING_PLACEHOLDER_SECONDARY_ACTIVITY_COMPONENT_NAME = new ComponentName(
                     FLICKER_APP_PACKAGE,
             FLICKER_APP_PACKAGE + ".ActivityEmbeddingPlaceholderSecondaryActivity");
+
+    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/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
similarity index 60%
copy from libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
copy to tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
index e62a63a..419d438 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeConstants.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailActivity.java
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.desktopmode;
+package com.android.server.wm.flicker.testapp;
 
-import android.os.SystemProperties;
+import android.os.Bundle;
 
-/**
- * Constants for desktop mode feature
- */
-public class DesktopModeConstants {
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
 
-    /**
-     * Flag to indicate whether desktop mode is available on the device
-     */
-    public static final boolean IS_FEATURE_ENABLED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
+public class MailActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_mail);
+    }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java
new file mode 100644
index 0000000..984263a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailAdapter.java
@@ -0,0 +1,134 @@
+/*
+ * 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.testapp;
+
+import static androidx.navigation.fragment.NavHostFragment.findNavController;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.graphics.drawable.shapes.Shape;
+import android.util.DisplayMetrics;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.navigation.NavController;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MailAdapter extends RecyclerView.Adapter<MailAdapter.ViewHolder> {
+
+    private final Fragment mFragment;
+    private final int mSize;
+
+    static class BadgeShape extends OvalShape {
+        Context mContext;
+        String mLabel;
+
+        BadgeShape(Context context, String label) {
+            mContext = context;
+            mLabel = label;
+        }
+
+        @Override
+        public void draw(Canvas canvas, Paint paint) {
+            final Resources resources = mContext.getResources();
+            int textSize = resources.getDimensionPixelSize(R.dimen.icon_text_size);
+            paint.setColor(Color.BLACK);
+            super.draw(canvas, paint);
+            paint.setColor(Color.WHITE);
+            paint.setTextSize(textSize);
+            paint.setTypeface(Typeface.DEFAULT_BOLD);
+            paint.setTextAlign(Paint.Align.CENTER);
+            Paint.FontMetrics fontMetrics = paint.getFontMetrics();
+            float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
+            canvas.drawText(
+                    mLabel,
+                    rect().centerX(),
+                    rect().centerY() + distance,
+                    paint);
+        }
+    }
+
+    static class ViewHolder extends RecyclerView.ViewHolder {
+
+        NavController mNavController;
+        ImageView mImageView;
+        TextView mTextView;
+        DisplayMetrics mDisplayMetrics;
+
+        ViewHolder(@NonNull View itemView, NavController navController) {
+            super(itemView);
+            mNavController = navController;
+            itemView.setOnClickListener(this::onClick);
+            mImageView = itemView.findViewById(R.id.mail_row_item_icon);
+            mTextView = itemView.findViewById(R.id.mail_row_item_text);
+            mDisplayMetrics = itemView.getContext().getResources().getDisplayMetrics();
+        }
+
+        void onClick(View v) {
+            mNavController.navigate(R.id.action_mail_list_to_mail_content);
+        }
+
+        public void setContent(int i) {
+            final Resources resources = mImageView.getContext().getResources();
+            final int badgeSize = resources.getDimensionPixelSize(R.dimen.icon_size);
+            final char c = (char) ('A' + i % 26);
+            final Shape badge = new BadgeShape(mImageView.getContext(), String.valueOf(c));
+            ShapeDrawable drawable = new ShapeDrawable();
+            drawable.setIntrinsicHeight(badgeSize);
+            drawable.setIntrinsicWidth(badgeSize);
+            drawable.setShape(badge);
+            mImageView.setImageDrawable(drawable);
+            mTextView.setText(String.format("%s-%04d", c, i));
+        }
+    }
+
+    public MailAdapter(Fragment fragment, int size) {
+        super();
+        mFragment = fragment;
+        mSize = size;
+    }
+
+    @NonNull
+    @Override
+    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
+        View v = LayoutInflater
+                .from(viewGroup.getContext())
+                .inflate(R.layout.mail_row_item, viewGroup, false);
+        return new ViewHolder(v, findNavController(mFragment));
+    }
+
+    @Override
+    public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
+        viewHolder.setContent(i);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSize;
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.java
new file mode 100644
index 0000000..278b92e
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailContentFragment.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.wm.flicker.testapp;
+
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+public class MailContentFragment extends Fragment {
+    public MailContentFragment() {
+        super(R.layout.fragment_mail_content);
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        view.setBackgroundColor(Color.LTGRAY);
+    }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java
new file mode 100644
index 0000000..551820c
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/MailListFragment.java
@@ -0,0 +1,49 @@
+/*
+ * 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.testapp;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class MailListFragment extends Fragment {
+
+    protected RecyclerView mRecyclerView;
+    protected RecyclerView.LayoutManager mLayoutManager;
+    protected MailAdapter mAdapter;
+
+    public MailListFragment() {
+        super(R.layout.fragment_mail_list);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        View rootView = inflater.inflate(R.layout.fragment_mail_list, container, false);
+        mRecyclerView = rootView.findViewById(R.id.mail_recycle_view);
+        mAdapter = new MailAdapter(this, 1000);
+        mRecyclerView.setAdapter(mAdapter);
+        mLayoutManager = new LinearLayoutManager(getActivity());
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        return rootView;
+    }
+}
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
index 8b69db7..dc34cb6 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/HandwritingIme.java
@@ -15,21 +15,25 @@
  */
 package com.google.android.test.handwritingime;
 
+import android.R;
 import android.annotation.Nullable;
 import android.graphics.PointF;
 import android.graphics.RectF;
 import android.inputmethodservice.InputMethodService;
-import android.os.Bundle;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
-import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.DeleteGesture;
+import android.view.inputmethod.HandwritingGesture;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InsertGesture;
+import android.view.inputmethod.SelectGesture;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import android.widget.Spinner;
 import android.widget.Toast;
 
@@ -39,19 +43,19 @@
 
     public static final int HEIGHT_DP = 100;
 
-
     private static final int OP_NONE = 0;
     private static final int OP_SELECT = 1;
     private static final int OP_DELETE = 2;
-    private static final int OP_DELETE_SPACE = 3;
-    private static final int OP_INSERT = 4;
+    private static final int OP_INSERT = 3;
 
     private Window mInkWindow;
     private InkView mInk;
 
     static final String TAG = "HandwritingIme";
     private int mRichGestureMode = OP_NONE;
+    private int mRichGestureGranularity = -1;
     private Spinner mRichGestureModeSpinner;
+    private Spinner mRichGestureGranularitySpinner;
     private PointF mRichGestureStartPoint;
 
 
@@ -86,13 +90,45 @@
         switch (event.getAction()) {
             case MotionEvent.ACTION_UP: {
                 if (areRichGesturesEnabled()) {
-                    Bundle bundle = new Bundle();
-                    bundle.putInt("operation", mRichGestureMode);
-                    bundle.putFloat("left", mRichGestureStartPoint.x);
-                    bundle.putFloat("top", mRichGestureStartPoint.y);
-                    bundle.putFloat("right", event.getX());
-                    bundle.putFloat("bottom", event.getY());
-                    performPrivateCommand("android.widget.RichGesture", bundle);
+                    HandwritingGesture gesture = null;
+                    switch(mRichGestureMode) {
+                        case OP_SELECT:
+                            SelectGesture.Builder builder = new SelectGesture.Builder();
+                            builder.setGranularity(mRichGestureGranularity)
+                                    .setSelectionArea(new RectF(mRichGestureStartPoint.x,
+                                            mRichGestureStartPoint.y, event.getX(), event.getY()))
+                                    .setFallbackText("fallback text");
+                            gesture = builder.build();
+                            break;
+                        case OP_DELETE:
+                            DeleteGesture.Builder builder1 = new DeleteGesture.Builder();
+                            builder1.setGranularity(mRichGestureGranularity)
+                                    .setDeletionArea(new RectF(mRichGestureStartPoint.x,
+                                            mRichGestureStartPoint.y, event.getX(), event.getY()))
+                                    .setFallbackText("fallback text");
+                            gesture = builder1.build();
+                            break;
+                        case OP_INSERT:
+                            InsertGesture.Builder builder2 = new InsertGesture.Builder();
+                            builder2.setInsertionPoint(
+                                    new PointF(mRichGestureStartPoint.x, mRichGestureStartPoint.y))
+                                    .setTextToInsert(" ")
+                                    .setFallbackText("fallback text");
+                            gesture = builder2.build();
+
+                    }
+                    if (gesture == null) {
+                        // This shouldn't happen
+                        Log.e(TAG, "Unrecognized gesture mode: " + mRichGestureMode);
+                        return;
+                    }
+                    InputConnection ic = getCurrentInputConnection();
+                    if (getCurrentInputStarted() && ic != null) {
+                        ic.performHandwritingGesture(gesture, null, null);
+                    } else {
+                        // This shouldn't happen
+                        Log.e(TAG, "No active InputConnection");
+                    }
 
                     Log.d(TAG, "Sending RichGesture " + mRichGestureMode + " (Screen) Left: "
                             + mRichGestureStartPoint.x + ", Top: " + mRichGestureStartPoint.y
@@ -123,8 +159,15 @@
         view.addView(inner, new FrameLayout.LayoutParams(
                 FrameLayout.LayoutParams.MATCH_PARENT, height));
 
-        view.addView(getRichGestureActionsSpinner());
-        inner.setBackgroundColor(getColor(R.color.abc_tint_spinner));
+        LinearLayout layout = new LinearLayout(this);
+        layout.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+        layout.setOrientation(LinearLayout.VERTICAL);
+        layout.addView(getRichGestureActionsSpinner());
+        layout.addView(getRichGestureGranularitySpinner());
+
+        view.addView(layout);
+        inner.setBackgroundColor(getColor(R.color.holo_green_light));
 
         return view;
     }
@@ -133,14 +176,12 @@
         if (mRichGestureModeSpinner != null) {
             return mRichGestureModeSpinner;
         }
-        //get the spinner from the xml.
         mRichGestureModeSpinner = new Spinner(this);
         mRichGestureModeSpinner.setPadding(100, 0, 100, 0);
         mRichGestureModeSpinner.setTooltipText("Handwriting IME mode");
         String[] items =
                 new String[] { "Handwriting IME - Rich gesture disabled", "Rich gesture SELECT",
-                        "Rich gesture DELETE", "Rich gesture DELETE SPACE",
-                        "Rich gesture INSERT" };
+                        "Rich gesture DELETE", "Rich gesture INSERT" };
         ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
                 android.R.layout.simple_spinner_dropdown_item, items);
         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -149,17 +190,52 @@
             @Override
             public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                 mRichGestureMode = position;
+                mRichGestureGranularitySpinner.setEnabled(
+                        mRichGestureMode != OP_INSERT && mRichGestureMode != OP_NONE);
                 Log.d(TAG, "Setting RichGesture Mode " + mRichGestureMode);
             }
 
             @Override
             public void onNothingSelected(AdapterView<?> parent) {
                 mRichGestureMode = OP_NONE;
+                mRichGestureGranularitySpinner.setEnabled(false);
             }
         });
+        mRichGestureModeSpinner.setSelection(0); // default disabled
         return mRichGestureModeSpinner;
     }
 
+    private View getRichGestureGranularitySpinner() {
+        if (mRichGestureGranularitySpinner != null) {
+            return mRichGestureGranularitySpinner;
+        }
+        mRichGestureGranularitySpinner = new Spinner(this);
+        mRichGestureGranularitySpinner.setPadding(100, 0, 100, 0);
+        mRichGestureGranularitySpinner.setTooltipText(" Granularity");
+        String[] items =
+                new String[] { "Granularity - UNDEFINED",
+                        "Granularity - WORD", "Granularity - CHARACTER"};
+        ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+                android.R.layout.simple_spinner_dropdown_item, items);
+        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        mRichGestureGranularitySpinner.setAdapter(adapter);
+        mRichGestureGranularitySpinner.setOnItemSelectedListener(
+                new AdapterView.OnItemSelectedListener() {
+            @Override
+            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+                mRichGestureGranularity = position;
+                Log.d(TAG, "Setting RichGesture Granularity " + mRichGestureGranularity);
+            }
+
+            @Override
+            public void onNothingSelected(AdapterView<?> parent) {
+                mRichGestureGranularity = 0;
+            }
+        });
+        mRichGestureGranularitySpinner.setSelection(1);
+        return mRichGestureGranularitySpinner;
+    }
+
     public void onPrepareStylusHandwriting() {
         Log.d(TAG, "onPrepareStylusHandwriting ");
         if (mInk == null) {
@@ -190,15 +266,6 @@
         return false;
     }
 
-    boolean performPrivateCommand(String action, Bundle bundle) {
-        if (!getCurrentInputStarted()) {
-            Log.e(TAG, "Input hasnt started, can't performPrivateCommand");
-            return false;
-        }
-
-        return getCurrentInputConnection().performPrivateCommand(action, bundle);
-    }
-
     private boolean areRichGesturesEnabled() {
         return mRichGestureMode != OP_NONE;
     }
diff --git a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
index c9e429b..94b1f86 100644
--- a/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
+++ b/tests/HandwritingIme/src/com/google/android/test/handwritingime/InkView.java
@@ -30,7 +30,7 @@
 import android.view.WindowMetrics;
 
 class InkView extends View {
-    private static final long FINISH_TIMEOUT = 600;
+    private static final long FINISH_TIMEOUT = 1500;
     private final HandwritingIme.HandwritingFinisher mHwCanceller;
     private final HandwritingIme.StylusConsumer mConsumer;
     private final int mTopInset;
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/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java
index 47f87d6..573b3b69 100644
--- a/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java
+++ b/tests/InputMethodStressTest/src/com/android/inputmethod/stresstest/NotificationTest.java
@@ -102,6 +102,7 @@
     @After
     public void tearDown() {
         mNotificationManager.cancelAll();
+        mUiDevice.pressHome();
     }
 
     @Test
diff --git a/tests/RollbackTest/Android.bp b/tests/RollbackTest/Android.bp
index 9f6ce4e..b7c4c5b 100644
--- a/tests/RollbackTest/Android.bp
+++ b/tests/RollbackTest/Android.bp
@@ -61,6 +61,7 @@
     static_libs: ["RollbackTestLib", "frameworks-base-hostutils"],
     test_suites: ["general-tests"],
     test_config: "NetworkStagedRollbackTest.xml",
+    data: [":RollbackTest"],
 }
 
 java_test_host {
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index 1709e15..ffde8c7 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -58,6 +58,7 @@
         ":apex.apexd_test",
         ":com.android.apex.apkrollback.test_v1",
         ":com.android.apex.apkrollback.test_v2",
+        ":StagedInstallInternalTestApp",
         ":StagedInstallTestApexV2",
         ":StagedInstallTestApexV2_WrongSha",
         ":TestAppAv1",
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index db48984..661dd84 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -33,6 +33,8 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import java.util.Arrays;
+
 public class MainInteractionSession extends VoiceInteractionSession
         implements View.OnClickListener {
     static final String TAG = "MainInteractionSession";
@@ -403,7 +405,7 @@
     @Override
     public void onRequestPickOption(PickOptionRequest request) {
         Log.i(TAG, "onPickOption: prompt=" + request.getVoicePrompt() + " options="
-                + request.getOptions() + " extras=" + request.getExtras());
+                + Arrays.toString(request.getOptions()) + " extras=" + request.getExtras());
         mConfirmButton.setText("Pick Option");
         mPendingRequest = request;
         setPrompt(request.getVoicePrompt());
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java
index 733f602..8ae7186 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/StartVoiceInteractionActivity.java
@@ -24,6 +24,8 @@
 import android.widget.Button;
 import android.widget.TextView;
 
+import java.util.Arrays;
+
 public class StartVoiceInteractionActivity extends Activity implements View.OnClickListener {
     static final String TAG = "LocalVoiceInteractionActivity";
 
@@ -187,7 +189,8 @@
         }
         @Override
         public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
-            Log.i(TAG, "Pick result: finished=" + finished + " selections=" + selections
+            Log.i(TAG, "Pick result: finished=" + finished
+                    + " selections=" + Arrays.toString(selections)
                     + " result=" + result);
             StringBuilder sb = new StringBuilder();
             if (finished) {
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index ada0e21..4fc3a15 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -28,6 +28,8 @@
 import android.widget.Button;
 import android.widget.TextView;
 
+import java.util.Arrays;
+
 public class TestInteractionActivity extends Activity implements View.OnClickListener {
     static final String TAG = "TestInteractionActivity";
 
@@ -240,7 +242,8 @@
         }
         @Override
         public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
-            Log.i(TAG, "Pick result: finished=" + finished + " selections=" + selections
+            Log.i(TAG, "Pick result: finished=" + finished
+                    + " selections=" + Arrays.toString(selections)
                     + " result=" + result);
             StringBuilder sb = new StringBuilder();
             if (finished) {
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index dfa2291..f9e52b4 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -33,6 +33,7 @@
 #include "ValueVisitor.h"
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
+#include "androidfw/ResourceTypes.h"
 #include "idmap2/Policies.h"
 #include "text/Printer.h"
 #include "util/Util.h"
@@ -515,7 +516,8 @@
   }
 
   void Visit(const xml::Text* text) override {
-    printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
+    printer_->Println(
+        StringPrintf("T: '%s'", android::ResTable::normalizeForOutput(text->text.c_str()).c_str()));
   }
 
  private:
diff --git a/tools/aapt2/cmd/Dump_test.cpp b/tools/aapt2/cmd/Dump_test.cpp
index 03da364..b1c69cd 100644
--- a/tools/aapt2/cmd/Dump_test.cpp
+++ b/tools/aapt2/cmd/Dump_test.cpp
@@ -59,6 +59,22 @@
   ASSERT_EQ(output, expected);
 }
 
+TEST_F(DumpTest, DumpBadgingMultipleUsesSdkTakesLatest) {
+  auto apk_path = file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests",
+                                   "DumpTest", "multiple_uses_sdk.apk"});
+  auto loaded_apk = LoadedApk::LoadApkFromPath(apk_path, &noop_diag);
+
+  std::string output;
+  DumpBadgingToString(loaded_apk.get(), &output);
+
+  std::string expected;
+  auto expected_path =
+      file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "DumpTest",
+                       "multiple_uses_sdk_expected.txt"});
+  ::android::base::ReadFileToString(expected_path, &expected);
+  ASSERT_EQ(output, expected);
+}
+
 TEST_F(DumpTest, DumpBadgingAllComponents) {
   auto apk_path = file::BuildPath(
       {android::base::GetExecutableDirectory(), "integration-tests", "DumpTest", "components.apk"});
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index b3165d3..c4c002d 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -448,7 +448,12 @@
   /** Recursively visit the xml element tree and return a processed badging element tree. */
   std::unique_ptr<Element> Visit(xml::Element* element);
 
-    /** Raises the target sdk value if the min target is greater than the current target. */
+  /** Resets target SDK to 0. */
+  void ResetTargetSdk() {
+    target_sdk_ = 0;
+  }
+
+  /** Raises the target sdk value if the min target is greater than the current target. */
   void RaiseTargetSdk(int32_t min_target) {
     if (min_target > target_sdk_) {
       target_sdk_ = min_target;
@@ -799,6 +804,10 @@
     target_sdk = GetAttributeInteger(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
     target_sdk_name = GetAttributeString(FindAttribute(element, TARGET_SDK_VERSION_ATTR));
 
+    // Resets target SDK first. This is required if APK contains multiple <uses-sdk> elements,
+    // we only need to take the latest values.
+    extractor()->ResetTargetSdk();
+
     // Detect the target sdk of the element
     if  ((min_sdk_name && *min_sdk_name == "Donut")
         || (target_sdk_name && *target_sdk_name == "Donut")) {
@@ -2845,7 +2854,9 @@
   supports_screen_->ToProtoScreens(out_badging, target_sdk_);
 
   for (auto& config : locales_) {
-    if (!config.first.empty()) {
+    if (config.first.empty()) {
+      out_badging->add_locales("--_--");
+    } else {
       out_badging->add_locales(config.first);
     }
   }
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 46a846b..4fb7ed1 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -369,9 +369,13 @@
 
     bool sparse_encode = use_sparse_entries_;
 
-    // Only sparse encode if the entries will be read on platforms O+.
-    sparse_encode =
-        sparse_encode && (context_->GetMinSdkVersion() >= SDK_O || config.sdkVersion >= SDK_O);
+    if (context_->GetMinSdkVersion() == 0 && config.sdkVersion == 0) {
+      // Sparse encode if sdk version is not set in context and config.
+    } else {
+      // Otherwise, only sparse encode if the entries will be read on platforms S_V2+.
+      sparse_encode = sparse_encode &&
+                      (context_->GetMinSdkVersion() >= SDK_S_V2 || config.sdkVersion >= SDK_S_V2);
+    }
 
     // Only sparse encode if the offsets are representable in 2 bytes.
     sparse_encode =
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index e48fca6..f551bf6 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -330,7 +330,7 @@
   std::unique_ptr<IAaptContext> context = test::ContextBuilder()
                                               .SetCompilationPackage("android")
                                               .SetPackageId(0x01)
-                                              .SetMinSdkVersion(SDK_O)
+                                              .SetMinSdkVersion(SDK_S_V2)
                                               .Build();
 
   const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB");
@@ -376,7 +376,7 @@
                                               .SetMinSdkVersion(SDK_LOLLIPOP)
                                               .Build();
 
-  const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB-v26");
+  const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB-v32");
   auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f);
 
   TableFlattenerOptions options;
@@ -391,6 +391,46 @@
   EXPECT_GT(no_sparse_contents.size(), sparse_contents.size());
 }
 
+TEST_F(TableFlattenerTest, FlattenSparseEntryWithSdkVersionNotSet) {
+  std::unique_ptr<IAaptContext> context =
+      test::ContextBuilder().SetCompilationPackage("android").SetPackageId(0x01).Build();
+
+  const ConfigDescription sparse_config = test::ParseConfigOrDie("en-rGB");
+  auto table_in = BuildTableWithSparseEntries(context.get(), sparse_config, 0.25f);
+
+  TableFlattenerOptions options;
+  options.use_sparse_entries = true;
+
+  std::string no_sparse_contents;
+  ASSERT_TRUE(Flatten(context.get(), {}, table_in.get(), &no_sparse_contents));
+
+  std::string sparse_contents;
+  ASSERT_TRUE(Flatten(context.get(), options, table_in.get(), &sparse_contents));
+
+  EXPECT_GT(no_sparse_contents.size(), sparse_contents.size());
+
+  // Attempt to parse the sparse contents.
+
+  ResourceTable sparse_table;
+  BinaryResourceParser parser(context->GetDiagnostics(), &sparse_table, Source("test.arsc"),
+                              sparse_contents.data(), sparse_contents.size());
+  ASSERT_TRUE(parser.Parse());
+
+  auto value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_0",
+                                                        sparse_config);
+  ASSERT_THAT(value, NotNull());
+  EXPECT_EQ(0u, value->value.data);
+
+  ASSERT_THAT(test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_1",
+                                                       sparse_config),
+              IsNull());
+
+  value = test::GetValueForConfig<BinaryPrimitive>(&sparse_table, "android:string/foo_4",
+                                                   sparse_config);
+  ASSERT_THAT(value, NotNull());
+  EXPECT_EQ(4u, value->value.data);
+}
+
 TEST_F(TableFlattenerTest, DoNotUseSparseEntryForDenseConfig) {
   std::unique_ptr<IAaptContext> context = test::ContextBuilder()
                                               .SetCompilationPackage("android")
diff --git a/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
index 7756410..4aed4af 100644
--- a/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
+++ b/tools/aapt2/integration-tests/DumpTest/components_expected_proto.txt
@@ -94,6 +94,7 @@
     provided_components: "camera"
     provided_components: "camera-secure"
   }
+  locales: "--_--"
   densities: 160
   densities: 240
   densities: 320
diff --git a/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
index 8e733a5..c783f47 100644
--- a/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
+++ b/tools/aapt2/integration-tests/DumpTest/components_full_proto.txt
@@ -94,6 +94,7 @@
     provided_components: "camera"
     provided_components: "camera-secure"
   }
+  locales: "--_--"
   densities: 160
   densities: 240
   densities: 320
diff --git a/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apk b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apk
new file mode 100644
index 0000000..7b269a5
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk.apk
Binary files differ
diff --git a/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt
new file mode 100644
index 0000000..85e8d0a
--- /dev/null
+++ b/tools/aapt2/integration-tests/DumpTest/multiple_uses_sdk_expected.txt
@@ -0,0 +1,23 @@
+package: name='com.test.e17wmultiapknexus' versionCode='107' versionName='14' platformBuildVersionName='2.3.3' platformBuildVersionCode='10'
+sdkVersion:'1'
+application-label:'w45wmultiapknexus_10'
+application-icon-120:'res/drawable-ldpi-v4/icon.png'
+application-icon-160:'res/drawable-mdpi-v4/icon.png'
+application-icon-240:'res/drawable-hdpi-v4/icon.png'
+application: label='w45wmultiapknexus_10' icon='res/drawable-mdpi-v4/icon.png'
+launchable-activity: name='com.test.e17wmultiapknexus.TestActivity'  label='' icon=''
+compatible-screens:'500/320'
+uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE'
+uses-implied-permission: name='android.permission.WRITE_EXTERNAL_STORAGE' reason='targetSdkVersion < 4'
+uses-permission: name='android.permission.READ_PHONE_STATE'
+uses-implied-permission: name='android.permission.READ_PHONE_STATE' reason='targetSdkVersion < 4'
+uses-permission: name='android.permission.READ_EXTERNAL_STORAGE'
+uses-implied-permission: name='android.permission.READ_EXTERNAL_STORAGE' reason='requested WRITE_EXTERNAL_STORAGE'
+feature-group: label=''
+  uses-feature: name='android.hardware.faketouch'
+  uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps'
+main
+supports-screens: 'small' 'normal' 'large' 'xlarge'
+supports-any-density: 'true'
+locales: '--_--'
+densities: '120' '160' '240'
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 = [email protected]()
+           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)
+}
diff --git a/tools/preload-check/AndroidTest.xml b/tools/preload-check/AndroidTest.xml
index a0645d5..d486f0f 100644
--- a/tools/preload-check/AndroidTest.xml
+++ b/tools/preload-check/AndroidTest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for PreloadCheck">
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
         <option name="cleanup" value="true" />
         <option name="push" value="preload-check-device.jar->/data/local/tmp/preload-check-device.jar" />
     </target_preparer>
diff --git a/tools/preload-check/OWNERS b/tools/preload-check/OWNERS
new file mode 100644
index 0000000..e71c733
--- /dev/null
+++ b/tools/preload-check/OWNERS
@@ -0,0 +1 @@
+include /ZYGOTE_OWNERS