Merge "[Bouncer] Make bouncer view a ConstraintLayout" into tm-qpr-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 41a784a..0126cb6 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -28,7 +28,7 @@
 
 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}
+ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}
 
 owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
 
diff --git a/apct-tests/perftests/surfaceflinger/AndroidTest.xml b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
index 53e5d99..11d1106 100644
--- a/apct-tests/perftests/surfaceflinger/AndroidTest.xml
+++ b/apct-tests/perftests/surfaceflinger/AndroidTest.xml
@@ -49,16 +49,20 @@
         <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
         <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
 
+        <option name="instrumentation-arg" key="profiling-iterations" value="525" />
         <!-- PerfettoListener related arguments -->
         <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
         <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
 
         <!-- SimpleperfListener related arguments -->
         <option name="instrumentation-arg" key="report" value="true" />
-        <option name="instrumentation-arg" key="arguments" value="&quot;&quot;" />
+        <option name="instrumentation-arg" key="arguments" value="-g" />
         <option name="instrumentation-arg" key="events_to_record" value="instructions,cpu-cycles,raw-l3d-cache-refill,sched:sched_waking" />
         <option name="instrumentation-arg" key="processes_to_record" value="surfaceflinger" />
-        <option name="instrumentation-arg" key="symbols_to_report" value="&quot;android::SurfaceFlinger::commit(;android::SurfaceFlinger::composite(&quot;" />
+        <option name="instrumentation-arg" key="symbols_to_report" value="&quot;commit;android::SurfaceFlinger::commit(;composite;android::SurfaceFlinger::composite(&quot;" />
+
+        <!-- should match profiling-iterations -->
+        <option name="instrumentation-arg" key="test_iterations" value="525" />
 
         <!-- ProcLoadListener related arguments -->
         <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
index 52fb8a6..8a447bb 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/BufferFlinger.java
@@ -53,15 +53,17 @@
         }
     }
 
-    public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl)
-            throws InterruptedException {
-        GraphicBuffer buffer = mBufferQ.take();
-        t.setBuffer(surfaceControl,
-                HardwareBuffer.createFromGraphicBuffer(buffer),
-                null,
-                (SyncFence fence) -> {
-                    releaseCallback(fence, buffer);
-                });
+    public void addBuffer(SurfaceControl.Transaction t, SurfaceControl surfaceControl) {
+        try {
+            final GraphicBuffer buffer = mBufferQ.take();
+            t.setBuffer(surfaceControl,
+                    HardwareBuffer.createFromGraphicBuffer(buffer),
+                    null,
+                    (SyncFence fence) -> {
+                        releaseCallback(fence, buffer);
+                    });
+        } catch (InterruptedException ignore) {
+        }
     }
 
     public void releaseCallback(SyncFence fence, GraphicBuffer buffer) {
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
index 45d164c..f92c297 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerPerfTest.java
@@ -18,8 +18,8 @@
 
 import android.graphics.Bitmap;
 import android.graphics.Color;
-import android.perftests.utils.BenchmarkState;
-import android.perftests.utils.PerfStatusReporter;
+import android.os.Bundle;
+import android.util.Log;
 import android.view.SurfaceControl;
 
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
@@ -29,6 +29,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -40,65 +41,35 @@
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class SurfaceFlingerPerfTest {
-    protected ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
+    private static final String TAG = "SurfaceFlingerPerfTest";
+    private final ActivityScenarioRule<SurfaceFlingerTestActivity> mActivityRule =
             new ActivityScenarioRule<>(SurfaceFlingerTestActivity.class);
-    protected PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
     private SurfaceFlingerTestActivity mActivity;
-    static final int BUFFER_COUNT = 2;
+    private static final int BUFFER_COUNT = 2;
+    private static final int MAX_BUFFERS = 10;
+    private static final int MAX_POSITION = 10;
+    private static final float MAX_SCALE = 2.0f;
+
+    private static final String ARGUMENT_PROFILING_ITERATIONS = "profiling-iterations";
+    private static final String DEFAULT_PROFILING_ITERATIONS = "100";
+    private static int sProfilingIterations;
+    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
 
     @Rule
     public final RuleChain mAllRules = RuleChain
-            .outerRule(mPerfStatusReporter)
-            .around(mActivityRule);
+            .outerRule(mActivityRule);
+
+    @BeforeClass
+    public static void suiteSetup() {
+        final Bundle arguments = InstrumentationRegistry.getArguments();
+        sProfilingIterations = Integer.parseInt(
+                arguments.getString(ARGUMENT_PROFILING_ITERATIONS, DEFAULT_PROFILING_ITERATIONS));
+        Log.d(TAG, "suiteSetup: mProfilingIterations = " + sProfilingIterations);
+    }
+
     @Before
     public void setup() {
         mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
-    }
-
-    @After
-    public void teardown() {
-        mSurfaceControls.forEach(SurfaceControl::release);
-        mByfferTrackers.forEach(BufferFlinger::freeBuffers);
-    }
-
-
-    private ArrayList<BufferFlinger> mByfferTrackers = new ArrayList<>();
-    private BufferFlinger createBufferTracker(int color) {
-        BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
-        mByfferTrackers.add(bufferTracker);
-        return bufferTracker;
-    }
-
-    private ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
-    private SurfaceControl createSurfaceControl() throws InterruptedException {
-        SurfaceControl sc = mActivity.createChildSurfaceControl();
-        mSurfaceControls.add(sc);
-        return sc;
-    }
-
-    @Test
-    public void singleBuffer() throws Exception {
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        bufferTracker.addBuffer(t, sc);
-        t.show(sc);
-
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
-            bufferTracker.addBuffer(t, sc);
-            t.apply();
-        }
-    }
-
-    static int getRandomColorComponent() {
-        return new Random().nextInt(155) + 100;
-    }
-
-    @Test
-    public void multipleBuffers() throws Exception {
-        final int MAX_BUFFERS = 10;
-
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         for (int i = 0; i < MAX_BUFFERS; i++) {
             SurfaceControl sc = createSurfaceControl();
@@ -107,122 +78,120 @@
                     getRandomColorComponent()));
             bufferTracker.addBuffer(t, sc);
             t.setPosition(sc, i * 10, i * 10);
-            t.show(sc);
         }
         t.apply(true);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+    }
+
+    @After
+    public void teardown() {
+        mSurfaceControls.forEach(SurfaceControl::release);
+        mBufferTrackers.forEach(BufferFlinger::freeBuffers);
+    }
+
+    static int getRandomColorComponent() {
+        return new Random().nextInt(155) + 100;
+    }
+
+    private final ArrayList<BufferFlinger> mBufferTrackers = new ArrayList<>();
+    private BufferFlinger createBufferTracker(int color) {
+        BufferFlinger bufferTracker = new BufferFlinger(BUFFER_COUNT, color);
+        mBufferTrackers.add(bufferTracker);
+        return bufferTracker;
+    }
+
+    private final ArrayList<SurfaceControl> mSurfaceControls = new ArrayList<>();
+    private SurfaceControl createSurfaceControl() {
+        SurfaceControl sc = mActivity.createChildSurfaceControl();
+        mSurfaceControls.add(sc);
+        return sc;
+    }
+
+    @Test
+    public void singleBuffer() throws Exception {
+        for (int i = 0; i < sProfilingIterations; i++) {
+            mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
+        }
+    }
+
+    @Test
+    public void multipleBuffers() throws Exception {
+        for (int j = 0; j < sProfilingIterations; j++) {
             for (int i = 0; i < MAX_BUFFERS; i++) {
-                mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
+                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
+                mTransaction.show(mSurfaceControls.get(i));
             }
-            t.apply();
+            mTransaction.apply(true);
         }
     }
 
     @Test
     public void multipleOpaqueBuffers() throws Exception {
-        final int MAX_BUFFERS = 10;
-
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        for (int i = 0; i < MAX_BUFFERS; i++) {
-            SurfaceControl sc = createSurfaceControl();
-            BufferFlinger bufferTracker = createBufferTracker(Color.rgb(getRandomColorComponent(),
-                    getRandomColorComponent(), getRandomColorComponent()));
-            bufferTracker.addBuffer(t, sc);
-            t.setOpaque(sc, true);
-            t.setPosition(sc, i * 10, i * 10);
-            t.show(sc);
-        }
-        t.apply(true);
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int j = 0; j < sProfilingIterations; j++) {
             for (int i = 0; i < MAX_BUFFERS; i++) {
-                mByfferTrackers.get(i).addBuffer(t, mSurfaceControls.get(i));
+                mBufferTrackers.get(i).addBuffer(mTransaction, mSurfaceControls.get(i));
+                mTransaction.show(mSurfaceControls.get(i)).setOpaque(mSurfaceControls.get(i), true);
             }
-            t.apply();
+            mTransaction.apply(true);
         }
     }
 
     @Test
     public void geometryChanges() throws Exception {
-        final int MAX_POSITION = 10;
-        final float MAX_SCALE = 2.0f;
-
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        bufferTracker.addBuffer(t, sc);
-        t.show(sc).apply(true);
-
         int step = 0;
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             step = ++step % MAX_POSITION;
-            t.setPosition(sc, step, step);
+            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
             float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
-            t.setScale(sc, scale, scale);
-            t.apply();
+            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
         }
     }
 
     @Test
     public void geometryWithBufferChanges() throws Exception {
-        final int MAX_POSITION = 10;
-
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-        bufferTracker.addBuffer(t, sc);
-        t.show(sc).apply(true);
-
         int step = 0;
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             step = ++step % MAX_POSITION;
-            t.setPosition(sc, step, step);
-            float scale = ((step * 2.0f) / MAX_POSITION) + 0.5f;
-            t.setScale(sc, scale, scale);
-            bufferTracker.addBuffer(t, sc);
-            t.apply();
+            mTransaction.setPosition(mSurfaceControls.get(0), step, step);
+            float scale = ((step * MAX_SCALE) / MAX_POSITION) + 0.5f;
+            mTransaction.setScale(mSurfaceControls.get(0), scale, scale);
+            mBufferTrackers.get(0).addBuffer(mTransaction, mSurfaceControls.get(0));
+            mTransaction.show(mSurfaceControls.get(0)).apply(true);
         }
     }
 
     @Test
     public void addRemoveLayers() throws Exception {
-        SurfaceControl sc = createSurfaceControl();
-        BufferFlinger bufferTracker = createBufferTracker(Color.GREEN);
-        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             SurfaceControl childSurfaceControl =  new SurfaceControl.Builder()
                     .setName("childLayer").setBLASTLayer().build();
-            bufferTracker.addBuffer(t, childSurfaceControl);
-            t.reparent(childSurfaceControl, sc);
-            t.apply();
-            t.remove(childSurfaceControl).apply();
+            mBufferTrackers.get(0).addBuffer(mTransaction, childSurfaceControl);
+            mTransaction.reparent(childSurfaceControl, mSurfaceControls.get(0));
+            mTransaction.show(childSurfaceControl).show(mSurfaceControls.get(0));
+            mTransaction.apply(true);
+            mTransaction.remove(childSurfaceControl).apply(true);
         }
     }
 
     @Test
     public void displayScreenshot() throws Exception {
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             Bitmap screenshot =
                     InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot();
             screenshot.recycle();
+            mTransaction.apply(true);
         }
     }
 
     @Test
     public void layerScreenshot() throws Exception {
-        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
-        while (state.keepRunning()) {
+        for (int i = 0; i < sProfilingIterations; i++) {
             Bitmap screenshot =
                     InstrumentationRegistry.getInstrumentation().getUiAutomation().takeScreenshot(
                             mActivity.getWindow());
             screenshot.recycle();
+            mTransaction.apply(true);
         }
     }
-
 }
diff --git a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
index 832a0cd..bb95659 100644
--- a/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
+++ b/apct-tests/perftests/surfaceflinger/src/android/surfaceflinger/SurfaceFlingerTestActivity.java
@@ -22,6 +22,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.Window;
 import android.view.WindowManager;
 
 import java.util.concurrent.CountDownLatch;
@@ -38,12 +39,15 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
+                WindowManager.LayoutParams.FLAG_FULLSCREEN);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         mTestSurfaceView = new TestSurfaceView(this);
         setContentView(mTestSurfaceView);
     }
 
-    public SurfaceControl createChildSurfaceControl() throws InterruptedException {
+    public SurfaceControl createChildSurfaceControl() {
         return mTestSurfaceView.getChildSurfaceControlHelper();
     }
 
@@ -65,8 +69,11 @@
             });
         }
 
-        public SurfaceControl getChildSurfaceControlHelper() throws InterruptedException {
-            mIsReady.await();
+        public SurfaceControl getChildSurfaceControlHelper() {
+            try {
+                mIsReady.await();
+            } catch (InterruptedException ignore) {
+            }
             SurfaceHolder holder = getHolder();
 
             // check to see if surface is valid
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 1b2d905..e263810 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -23,6 +23,7 @@
 #include <cstring>
 #include <filesystem>
 #include <fstream>
+#include <limits>
 #include <memory>
 #include <ostream>
 #include <string>
@@ -295,26 +296,42 @@
   return ok();
 }
 
-Status Idmap2Service::acquireFabricatedOverlayIterator() {
+Status Idmap2Service::acquireFabricatedOverlayIterator(int32_t* _aidl_return) {
+  std::lock_guard l(frro_iter_mutex_);
   if (frro_iter_.has_value()) {
     LOG(WARNING) << "active ffro iterator was not previously released";
   }
   frro_iter_ = std::filesystem::directory_iterator(kIdmapCacheDir);
+  if (frro_iter_id_ == std::numeric_limits<int32_t>::max()) {
+    frro_iter_id_ = 0;
+  } else {
+    ++frro_iter_id_;
+  }
+  *_aidl_return = frro_iter_id_;
   return ok();
 }
 
-Status Idmap2Service::releaseFabricatedOverlayIterator() {
+Status Idmap2Service::releaseFabricatedOverlayIterator(int32_t iteratorId) {
+  std::lock_guard l(frro_iter_mutex_);
   if (!frro_iter_.has_value()) {
     LOG(WARNING) << "no active ffro iterator to release";
+  } else if (frro_iter_id_ != iteratorId) {
+    LOG(WARNING) << "incorrect iterator id in a call to release";
+  } else {
+    frro_iter_.reset();
   }
   return ok();
 }
 
-Status Idmap2Service::nextFabricatedOverlayInfos(
+Status Idmap2Service::nextFabricatedOverlayInfos(int32_t iteratorId,
     std::vector<os::FabricatedOverlayInfo>* _aidl_return) {
+  std::lock_guard l(frro_iter_mutex_);
+
   constexpr size_t kMaxEntryCount = 100;
   if (!frro_iter_.has_value()) {
     return error("no active frro iterator");
+  } else if (frro_iter_id_ != iteratorId) {
+    return error("incorrect iterator id in a call to next");
   }
 
   size_t count = 0;
@@ -322,22 +339,22 @@
   auto entry_iter_end = end(*frro_iter_);
   for (; entry_iter != entry_iter_end && count < kMaxEntryCount; ++entry_iter) {
     auto& entry = *entry_iter;
-    if (!entry.is_regular_file() || !android::IsFabricatedOverlay(entry.path())) {
+    if (!entry.is_regular_file() || !android::IsFabricatedOverlay(entry.path().native())) {
       continue;
     }
 
-    const auto overlay = FabricatedOverlayContainer::FromPath(entry.path());
+    const auto overlay = FabricatedOverlayContainer::FromPath(entry.path().native());
     if (!overlay) {
       LOG(WARNING) << "Failed to open '" << entry.path() << "': " << overlay.GetErrorMessage();
       continue;
     }
 
-    const auto info = (*overlay)->GetManifestInfo();
+    auto info = (*overlay)->GetManifestInfo();
     os::FabricatedOverlayInfo out_info;
-    out_info.packageName = info.package_name;
-    out_info.overlayName = info.name;
-    out_info.targetPackageName = info.target_package;
-    out_info.targetOverlayable = info.target_name;
+    out_info.packageName = std::move(info.package_name);
+    out_info.overlayName = std::move(info.name);
+    out_info.targetPackageName = std::move(info.target_package);
+    out_info.targetOverlayable = std::move(info.target_name);
     out_info.path = entry.path();
     _aidl_return->emplace_back(std::move(out_info));
     count++;
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index c61e4bc..cc8cc5f 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -26,7 +26,10 @@
 
 #include <filesystem>
 #include <memory>
+#include <mutex>
+#include <optional>
 #include <string>
+#include <variant>
 #include <vector>
 
 namespace android::os {
@@ -60,11 +63,11 @@
   binder::Status deleteFabricatedOverlay(const std::string& overlay_path,
                                          bool* _aidl_return) override;
 
-  binder::Status acquireFabricatedOverlayIterator() override;
+  binder::Status acquireFabricatedOverlayIterator(int32_t* _aidl_return) override;
 
-  binder::Status releaseFabricatedOverlayIterator() override;
+  binder::Status releaseFabricatedOverlayIterator(int32_t iteratorId) override;
 
-  binder::Status nextFabricatedOverlayInfos(
+  binder::Status nextFabricatedOverlayInfos(int32_t iteratorId,
       std::vector<os::FabricatedOverlayInfo>* _aidl_return) override;
 
   binder::Status dumpIdmap(const std::string& overlay_path, std::string* _aidl_return) override;
@@ -74,7 +77,9 @@
   // be able to be recalculated if idmap2 dies and restarts.
   std::unique_ptr<idmap2::TargetResourceContainer> framework_apk_cache_;
 
+  int32_t frro_iter_id_ = 0;
   std::optional<std::filesystem::directory_iterator> frro_iter_;
+  std::mutex frro_iter_mutex_;
 
   template <typename T>
   using MaybeUniquePtr = std::variant<std::unique_ptr<T>, T*>;
diff --git a/cmds/idmap2/idmap2d/aidl/services/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/services/android/os/IIdmap2.aidl
index 0059cf2..2bbfba9 100644
--- a/cmds/idmap2/idmap2d/aidl/services/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/services/android/os/IIdmap2.aidl
@@ -41,9 +41,9 @@
   @nullable FabricatedOverlayInfo createFabricatedOverlay(in FabricatedOverlayInternal overlay);
   boolean deleteFabricatedOverlay(@utf8InCpp String path);
 
-  void acquireFabricatedOverlayIterator();
-  void releaseFabricatedOverlayIterator();
-  List<FabricatedOverlayInfo> nextFabricatedOverlayInfos();
+  int acquireFabricatedOverlayIterator();
+  void releaseFabricatedOverlayIterator(int iteratorId);
+  List<FabricatedOverlayInfo> nextFabricatedOverlayInfos(int iteratorId);
 
   @utf8InCpp String dumpIdmap(@utf8InCpp String overlayApkPath);
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7c1f9c8..855366a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8045,8 +8045,9 @@
                 resultData.prepareToLeaveProcess(this);
             }
             upIntent.prepareToLeaveProcess(this);
-            return ActivityClient.getInstance().navigateUpTo(mToken, upIntent, resultCode,
-                    resultData);
+            String resolvedType = upIntent.resolveTypeIfNeeded(getContentResolver());
+            return ActivityClient.getInstance().navigateUpTo(mToken, upIntent, resolvedType,
+                    resultCode, resultData);
         } else {
             return mParent.navigateUpToFromChild(this, upIntent);
         }
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 482f456..d1e6780 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -141,11 +141,11 @@
         }
     }
 
-    boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
+    boolean navigateUpTo(IBinder token, Intent destIntent, String resolvedType, int resultCode,
             Intent resultData) {
         try {
-            return getActivityClientController().navigateUpTo(token, destIntent, resultCode,
-                    resultData);
+            return getActivityClientController().navigateUpTo(token, destIntent, resolvedType,
+                    resultCode, resultData);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 61cca00..0c08735 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -257,6 +257,12 @@
     private static final String KEY_LAUNCH_TASK_ID = "android.activity.launchTaskId";
 
     /**
+     * See {@link #setDisableStartingWindow}.
+     * @hide
+     */
+    private static final String KEY_DISABLE_STARTING_WINDOW = "android.activity.disableStarting";
+
+    /**
      * See {@link #setPendingIntentLaunchFlags(int)}
      * @hide
      */
@@ -467,6 +473,7 @@
     private PictureInPictureParams mLaunchIntoPipParams;
     private boolean mDismissKeyguard;
     private boolean mIgnorePendingIntentCreatorForegroundState;
+    private boolean mDisableStartingWindow;
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -1272,6 +1279,7 @@
         mDismissKeyguard = opts.getBoolean(KEY_DISMISS_KEYGUARD);
         mIgnorePendingIntentCreatorForegroundState = opts.getBoolean(
                 KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE);
+        mDisableStartingWindow = opts.getBoolean(KEY_DISABLE_STARTING_WINDOW);
     }
 
     /**
@@ -1671,6 +1679,22 @@
     }
 
     /**
+     * Sets whether recents disable showing starting window when activity launch.
+     * @hide
+     */
+    @RequiresPermission(START_TASKS_FROM_RECENTS)
+    public void setDisableStartingWindow(boolean disable) {
+        mDisableStartingWindow = disable;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean getDisableStartingWindow() {
+        return mDisableStartingWindow;
+    }
+
+    /**
      * Specifies intent flags to be applied for any activity started from a PendingIntent.
      *
      * @hide
@@ -2178,6 +2202,9 @@
             b.putBoolean(KEY_IGNORE_PENDING_INTENT_CREATOR_FOREGROUND_STATE,
                     mIgnorePendingIntentCreatorForegroundState);
         }
+        if (mDisableStartingWindow) {
+            b.putBoolean(KEY_DISABLE_STARTING_WINDOW, mDisableStartingWindow);
+        }
         return b;
     }
 
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index f0e1448..aa5fa5b 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -528,6 +528,28 @@
         return mIsAlarmBroadcast;
     }
 
+    /**
+     * Did this broadcast originate from a push message from the server?
+     *
+     * @return true if this broadcast is a push message, false otherwise.
+     * @hide
+     */
+    public boolean isPushMessagingBroadcast() {
+        return mTemporaryAppAllowlistReasonCode == PowerExemptionManager.REASON_PUSH_MESSAGING;
+    }
+
+    /**
+     * Did this broadcast originate from a push message from the server which was over the allowed
+     * quota?
+     *
+     * @return true if this broadcast is a push message over quota, false otherwise.
+     * @hide
+     */
+    public boolean isPushMessagingOverQuotaBroadcast() {
+        return mTemporaryAppAllowlistReasonCode
+                == PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA;
+    }
+
     /** {@hide} */
     public long getRequireCompatChangeId() {
         return mRequireCompatChangeId;
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index f5e5cda..9aa67bc 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -60,8 +60,8 @@
             in SizeConfigurationBuckets sizeConfigurations);
     boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
     boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
-    boolean navigateUpTo(in IBinder token, in Intent target, int resultCode,
-            in Intent resultData);
+    boolean navigateUpTo(in IBinder token, in Intent target, in String resolvedType,
+            int resultCode, in Intent resultData);
     boolean releaseActivityInstance(in IBinder token);
     boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
     boolean finishActivityAffinity(in IBinder token);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e820733..f320b74 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4453,6 +4453,10 @@
          * <p>Apps targeting {@link Build.VERSION_CODES#Q} and above will have to request
          * a permission ({@link android.Manifest.permission#USE_FULL_SCREEN_INTENT}) in order to
          * use full screen intents.</p>
+         * <p>
+         * To be launched as a full screen intent, the notification must also be posted to a
+         * channel with importance level set to IMPORTANCE_HIGH or higher.
+         * </p>
          *
          * @param intent The pending intent to launch.
          * @param highPriority Passing true will cause this notification to be sent
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 34c91c3..8e09939 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -12150,6 +12150,15 @@
      * Attempts by the admin to grant these permissions, when the admin is restricted from doing
      * so, will be silently ignored (no exception will be thrown).
      *
+     * Control over the following permissions are restricted for managed profile owners:
+     * <ul>
+     *  <li>Manifest.permission.READ_SMS</li>
+     * </ul>
+     * <p>
+     * A managed profile owner may not grant these permissions (i.e. call this method with any of
+     * the permissions listed above and {@code grantState} of
+     * {@code #PERMISSION_GRANT_STATE_GRANTED}), but may deny them.
+     *
      * @param admin Which profile or device owner this request is associated with.
      * @param packageName The application to grant or revoke a permission to.
      * @param permission The permission to grant or revoke.
diff --git a/core/java/android/app/smartspace/SmartspaceTarget.java b/core/java/android/app/smartspace/SmartspaceTarget.java
index 79d7b21..3c66a15 100644
--- a/core/java/android/app/smartspace/SmartspaceTarget.java
+++ b/core/java/android/app/smartspace/SmartspaceTarget.java
@@ -245,6 +245,10 @@
     public static final int UI_TEMPLATE_COMBINED_CARDS = 6;
     // Sub-card template whose data is represented by {@link SubCardTemplateData}
     public static final int UI_TEMPLATE_SUB_CARD = 7;
+    // Reserved: 8
+    // Template type used by non-UI template features for sending logging information in the
+    // base template data. This should not be used for UI template features.
+    // public static final int UI_TEMPLATE_LOGGING_ONLY = 8;
 
     /**
      * The types of the Smartspace ui templates.
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 9e87037..90e92db 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -159,8 +159,9 @@
      *
      * <li> For a SurfaceView output surface, the timestamp base is {@link
      * #TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED}. The timestamp is overridden with choreographer
-     * pulses from the display subsystem for smoother display of camera frames. The timestamp
-     * is roughly in the same time base as {@link android.os.SystemClock#uptimeMillis}.</li>
+     * pulses from the display subsystem for smoother display of camera frames when the camera
+     * device runs in fixed frame rate. The timestamp is roughly in the same time base as
+     * {@link android.os.SystemClock#uptimeMillis}.</li>
      * <li> For an output surface of MediaRecorder, MediaCodec, or ImageReader with {@link
      * android.hardware.HardwareBuffer#USAGE_VIDEO_ENCODE} usge flag, the timestamp base is
      * {@link #TIMESTAMP_BASE_MONOTONIC}, which is roughly the same time base as
@@ -231,7 +232,8 @@
      *
      * <p>The timestamp of the output images are overridden with choreographer pulses from the
      * display subsystem for smoother display of camera frames. An output target of SurfaceView
-     * uses this time base by default.</p>
+     * uses this time base by default. Note that the timestamp override is done for fixed camera
+     * frame rate only.</p>
      *
      * <p>This timestamp base isn't applicable to SurfaceTexture targets. SurfaceTexture's
      * {@link android.graphics.SurfaceTexture#updateTexImage updateTexImage} function always
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 2da12e6c..a645ae4 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;
@@ -155,4 +156,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 d17a952..97812ce 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;
@@ -66,6 +67,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;
 import com.android.internal.util.ArrayUtils;
@@ -74,6 +76,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.
@@ -111,6 +115,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.
@@ -1752,6 +1764,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 {
@@ -1861,4 +1996,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/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 06c35b5..3d5c34c 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -962,7 +962,7 @@
          * also be bumped.
          */
         static final String[] USER_ACTIVITY_TYPES = {
-            "other", "button", "touch", "accessibility", "attention"
+            "other", "button", "touch", "accessibility", "attention", "faceDown", "deviceState"
         };
 
         public static final int NUM_USER_ACTIVITY_TYPES = USER_ACTIVITY_TYPES.length;
diff --git a/core/java/android/os/BatteryUsageStats.java b/core/java/android/os/BatteryUsageStats.java
index 58f9336..26e5e95 100644
--- a/core/java/android/os/BatteryUsageStats.java
+++ b/core/java/android/os/BatteryUsageStats.java
@@ -34,6 +34,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;
@@ -449,6 +450,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 BatteryConsumer deviceBatteryConsumer = getAggregateBatteryConsumer(
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 3d70138..a7349f9 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -4388,6 +4388,9 @@
         int type = readInt();
         if (isLengthPrefixed(type)) {
             int objectLength = readInt();
+            if (objectLength < 0) {
+                return null;
+            }
             int end = MathUtils.addOrThrow(dataPosition(), objectLength);
             int valueLength = end - start;
             setDataPosition(end);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 13ca2c3..a46868e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -345,6 +345,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/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index 6956cd4..295171c 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -29,16 +29,18 @@
      *
      * @param doze If true, starts the doze dream component if one has been configured,
      * otherwise starts the user-specified dream.
+     * @param reason The reason to start dreaming, which is logged to help debugging.
      */
-    public abstract void startDream(boolean doze);
+    public abstract void startDream(boolean doze, String reason);
 
     /**
      * Called by the power manager to stop a dream.
      *
      * @param immediate If true, ends the dream summarily, otherwise gives it some time
      * to perform a proper exit transition.
+     * @param reason The reason to stop dreaming, which is logged to help debugging.
      */
-    public abstract void stopDream(boolean immediate);
+    public abstract void stopDream(boolean immediate, String reason);
 
     /**
      * Called by the power manager to determine whether a dream is running.
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index d066ee7..3b7698e3 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -31,9 +31,9 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
@@ -68,6 +68,8 @@
 
 import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
+import com.android.internal.util.ObservableServiceConnection;
+import com.android.internal.util.PersistentServiceConnection;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -75,7 +77,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 
 /**
@@ -225,6 +228,7 @@
 
     /**
      * The default value for whether to show complications on the overlay.
+     *
      * @hide
      */
     public static final boolean DEFAULT_SHOW_COMPLICATIONS = false;
@@ -251,77 +255,66 @@
     private DreamServiceWrapper mDreamServiceWrapper;
     private Runnable mDispatchAfterOnAttachedToWindow;
 
-    private final OverlayConnection mOverlayConnection;
+    private OverlayConnection mOverlayConnection;
 
-    private static class OverlayConnection implements ServiceConnection {
+    private static class OverlayConnection extends PersistentServiceConnection<IDreamOverlay> {
         // Overlay set during onBind.
         private IDreamOverlay mOverlay;
-        // A Queue of pending requests to execute on the overlay.
-        private final ArrayDeque<Consumer<IDreamOverlay>> mRequests;
+        // A list of pending requests to execute on the overlay.
+        private final ArrayList<Consumer<IDreamOverlay>> mConsumers = new ArrayList<>();
 
-        private boolean mBound;
-
-        OverlayConnection() {
-            mRequests = new ArrayDeque<>();
-        }
-
-        public void bind(Context context, @Nullable ComponentName overlayService,
-                ComponentName dreamService) {
-            if (overlayService == null) {
-                return;
+        private final Callback<IDreamOverlay> mCallback = new Callback<IDreamOverlay>() {
+            @Override
+            public void onConnected(ObservableServiceConnection<IDreamOverlay> connection,
+                    IDreamOverlay service) {
+                mOverlay = service;
+                for (Consumer<IDreamOverlay> consumer : mConsumers) {
+                    consumer.accept(mOverlay);
+                }
             }
 
-            final ServiceInfo serviceInfo = fetchServiceInfo(context, dreamService);
-
-            final Intent overlayIntent = new Intent();
-            overlayIntent.setComponent(overlayService);
-            overlayIntent.putExtra(EXTRA_SHOW_COMPLICATIONS,
-                    fetchShouldShowComplications(context, serviceInfo));
-            overlayIntent.putExtra(EXTRA_DREAM_COMPONENT, dreamService);
-
-            context.bindService(overlayIntent,
-                    this, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE);
-            mBound = true;
-        }
-
-        public void unbind(Context context) {
-            if (!mBound) {
-                return;
+            @Override
+            public void onDisconnected(ObservableServiceConnection<IDreamOverlay> connection,
+                    int reason) {
+                mOverlay = null;
             }
+        };
 
-            context.unbindService(this);
-            mBound = false;
-        }
-
-        public void request(Consumer<IDreamOverlay> request) {
-            mRequests.push(request);
-            evaluate();
-        }
-
-        private void evaluate() {
-            if (mOverlay == null) {
-                return;
-            }
-
-            // Any new requests that arrive during this loop will be processed synchronously after
-            // the loop exits.
-            while (!mRequests.isEmpty()) {
-                final Consumer<IDreamOverlay> request = mRequests.pop();
-                request.accept(mOverlay);
-            }
+        OverlayConnection(Context context,
+                Executor executor,
+                Handler handler,
+                ServiceTransformer<IDreamOverlay> transformer,
+                Intent serviceIntent,
+                int flags,
+                int minConnectionDurationMs,
+                int maxReconnectAttempts,
+                int baseReconnectDelayMs) {
+            super(context, executor, handler, transformer, serviceIntent, flags,
+                    minConnectionDurationMs,
+                    maxReconnectAttempts, baseReconnectDelayMs);
         }
 
         @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            // Store Overlay and execute pending requests.
-            mOverlay = IDreamOverlay.Stub.asInterface(service);
-            evaluate();
+        public boolean bind() {
+            addCallback(mCallback);
+            return super.bind();
         }
 
         @Override
-        public void onServiceDisconnected(ComponentName name) {
-            // Clear Overlay binder to prevent further request processing.
-            mOverlay = null;
+        public void unbind() {
+            removeCallback(mCallback);
+            super.unbind();
+        }
+
+        public void addConsumer(Consumer<IDreamOverlay> consumer) {
+            mConsumers.add(consumer);
+            if (mOverlay != null) {
+                consumer.accept(mOverlay);
+            }
+        }
+
+        public void removeConsumer(Consumer<IDreamOverlay> consumer) {
+            mConsumers.remove(consumer);
         }
     }
 
@@ -336,7 +329,6 @@
 
     public DreamService() {
         mDreamManager = IDreamManager.Stub.asInterface(ServiceManager.getService(DREAM_SERVICE));
-        mOverlayConnection = new OverlayConnection();
     }
 
     /**
@@ -532,7 +524,7 @@
         return mWindow;
     }
 
-   /**
+    /**
      * Inflates a layout resource and set it to be the content view for this Dream.
      * Behaves similarly to {@link android.app.Activity#setContentView(int)}.
      *
@@ -996,13 +988,33 @@
     public final IBinder onBind(Intent intent) {
         if (mDebug) Slog.v(mTag, "onBind() intent = " + intent);
         mDreamServiceWrapper = new DreamServiceWrapper();
+        final ComponentName overlayComponent = intent.getParcelableExtra(
+                EXTRA_DREAM_OVERLAY_COMPONENT, ComponentName.class);
 
         // Connect to the overlay service if present.
-        if (!mWindowless) {
-            mOverlayConnection.bind(
+        if (!mWindowless && overlayComponent != null) {
+            final Resources resources = getResources();
+            final ComponentName dreamService = new ComponentName(this, getClass());
+
+            final ServiceInfo serviceInfo = fetchServiceInfo(this, dreamService);
+            final Intent overlayIntent = new Intent()
+                    .setComponent(overlayComponent)
+                    .putExtra(EXTRA_SHOW_COMPLICATIONS,
+                            fetchShouldShowComplications(this, serviceInfo))
+                    .putExtra(EXTRA_DREAM_COMPONENT, dreamService);
+
+            mOverlayConnection = new OverlayConnection(
                     /* context= */ this,
-                    intent.getParcelableExtra(EXTRA_DREAM_OVERLAY_COMPONENT),
-                    new ComponentName(this, getClass()));
+                    getMainExecutor(),
+                    mHandler,
+                    IDreamOverlay.Stub::asInterface,
+                    overlayIntent,
+                    /* flags= */ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                    resources.getInteger(R.integer.config_minDreamOverlayDurationMs),
+                    resources.getInteger(R.integer.config_dreamOverlayMaxReconnectAttempts),
+                    resources.getInteger(R.integer.config_dreamOverlayReconnectTimeoutMs));
+
+            mOverlayConnection.bind();
         }
 
         return mDreamServiceWrapper;
@@ -1011,7 +1023,9 @@
     @Override
     public boolean onUnbind(Intent intent) {
         // We must unbind from any overlay connection if we are unbound before finishing.
-        mOverlayConnection.unbind(this);
+        if (mOverlayConnection != null) {
+            mOverlayConnection.unbind();
+        }
 
         return super.onUnbind(intent);
     }
@@ -1040,7 +1054,9 @@
         }
         mFinished = true;
 
-        mOverlayConnection.unbind(this);
+        if (mOverlayConnection != null) {
+            mOverlayConnection.unbind();
+        }
 
         if (mDreamToken == null) {
             Slog.w(mTag, "Finish was called before the dream was attached.");
@@ -1337,19 +1353,24 @@
 
         mWindow.getDecorView().addOnAttachStateChangeListener(
                 new View.OnAttachStateChangeListener() {
+                    private Consumer<IDreamOverlay> mDreamStartOverlayConsumer;
+
                     @Override
                     public void onViewAttachedToWindow(View v) {
                         mDispatchAfterOnAttachedToWindow.run();
 
-                        // Request the DreamOverlay be told to dream with dream's window parameters
-                        // once the window has been attached.
-                        mOverlayConnection.request(overlay -> {
-                            try {
-                                overlay.startDream(mWindow.getAttributes(), mOverlayCallback);
-                            } catch (RemoteException e) {
-                                Log.e(mTag, "could not send window attributes:" + e);
-                            }
-                        });
+                        if (mOverlayConnection != null) {
+                            // Request the DreamOverlay be told to dream with dream's window
+                            // parameters once the window has been attached.
+                            mDreamStartOverlayConsumer = overlay -> {
+                                try {
+                                    overlay.startDream(mWindow.getAttributes(), mOverlayCallback);
+                                } catch (RemoteException e) {
+                                    Log.e(mTag, "could not send window attributes:" + e);
+                                }
+                            };
+                            mOverlayConnection.addConsumer(mDreamStartOverlayConsumer);
+                        }
                     }
 
                     @Override
@@ -1362,6 +1383,9 @@
                             mActivity = null;
                             finish();
                         }
+                        if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) {
+                            mOverlayConnection.removeConsumer(mDreamStartOverlayConsumer);
+                        }
                     }
                 });
     }
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index fae72a2..ced2a01 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,28 +75,32 @@
     }
 
     private static void startDream(Context context, boolean docked) {
-        DreamManagerInternal dreamManagerService =
-                LocalServices.getService(DreamManagerInternal.class);
-        if (dreamManagerService != null && !dreamManagerService.isDreaming()) {
-            if (docked) {
-                Slog.i(TAG, "Activating dream while 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.");
 
-                // 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.");
+                    // 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();
             }
-
-            // Dream.
-            dreamManagerService.requestDream();
+        } catch (RemoteException ex) {
+            Slog.e(TAG, "Could not start dream when docked.", ex);
         }
     }
 
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java
index 206e4fa..e5ad85c 100644
--- a/core/java/android/service/notification/NotificationStats.java
+++ b/core/java/android/service/notification/NotificationStats.java
@@ -42,7 +42,8 @@
 
     /** @hide */
     @IntDef(prefix = { "DISMISSAL_SURFACE_" }, value = {
-            DISMISSAL_NOT_DISMISSED, DISMISSAL_OTHER, DISMISSAL_PEEK, DISMISSAL_AOD, DISMISSAL_SHADE
+            DISMISSAL_NOT_DISMISSED, DISMISSAL_OTHER, DISMISSAL_PEEK, DISMISSAL_AOD,
+            DISMISSAL_SHADE, DISMISSAL_BUBBLE, DISMISSAL_LOCKSCREEN
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DismissalSurface {}
@@ -75,7 +76,12 @@
      * Notification has been dismissed as a bubble.
      * @hide
      */
-    public static final int DISMISSAL_BUBBLE = 3;
+    public static final int DISMISSAL_BUBBLE = 4;
+    /**
+     * Notification has been dismissed from the lock screen.
+     * @hide
+     */
+    public static final int DISMISSAL_LOCKSCREEN = 5;
 
     /** @hide */
     @IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = {
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7d56039..7164412 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -1022,6 +1022,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/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 5832527..c8c941a 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -22,6 +22,7 @@
 import static android.view.InsetsSourceProto.VISIBLE_FRAME;
 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
 import static android.view.InsetsState.ITYPE_IME;
+import static android.view.ViewRootImpl.CAPTION_ON_SHELL;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -148,7 +149,7 @@
         // During drag-move and drag-resizing, the caption insets position may not get updated
         // before the app frame get updated. To layout the app content correctly during drag events,
         // we always return the insets with the corresponding height covering the top.
-        if (getType() == ITYPE_CAPTION_BAR) {
+        if (!CAPTION_ON_SHELL && getType() == ITYPE_CAPTION_BAR) {
             return Insets.of(0, frame.height(), 0, 0);
         }
         // Checks for whether there is shared edge with insets for 0-width/height window.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e4caa38..4522c0d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1099,6 +1099,10 @@
                 mInputQueueCallback.onInputQueueCreated(mInputQueue);
             }
         }
+
+        // Update the last resource config in case the resource configuration was changed while
+        // activity relaunched.
+        updateLastConfigurationFromResources(getConfiguration());
     }
 
     private Configuration getConfiguration() {
@@ -5392,13 +5396,7 @@
             // Update the display with new DisplayAdjustments.
             updateInternalDisplay(mDisplay.getDisplayId(), localResources);
 
-            final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
-            final int currentLayoutDirection = config.getLayoutDirection();
-            mLastConfigurationFromResources.setTo(config);
-            if (lastLayoutDirection != currentLayoutDirection
-                    && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
-                mView.setLayoutDirection(currentLayoutDirection);
-            }
+            updateLastConfigurationFromResources(config);
             mView.dispatchConfigurationChanged(config);
 
             // We could have gotten this {@link Configuration} update after we called
@@ -5412,6 +5410,17 @@
         updateForceDarkMode();
     }
 
+    private void updateLastConfigurationFromResources(Configuration resConfig) {
+        final int lastLayoutDirection = mLastConfigurationFromResources.getLayoutDirection();
+        final int currentLayoutDirection = resConfig.getLayoutDirection();
+        mLastConfigurationFromResources.setTo(resConfig);
+        // Update layout direction in case the language or screen layout is changed.
+        if (lastLayoutDirection != currentLayoutDirection && mView != null
+                && mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
+            mView.setLayoutDirection(currentLayoutDirection);
+        }
+    }
+
     /**
      * Return true if child is an ancestor of parent, (or equal to the parent).
      */
@@ -8154,6 +8163,7 @@
                     mLastSyncSeqId, mTmpFrames, mPendingMergedConfiguration, mSurfaceControl,
                     mTempInsets, mTempControls, mRelayoutBundle);
             mRelayoutRequested = true;
+
             final int maybeSyncSeqId = mRelayoutBundle.getInt("seqid");
             if (maybeSyncSeqId > 0) {
                 mSyncSeqId = maybeSyncSeqId;
@@ -8193,6 +8203,12 @@
             }
         }
 
+        if (mSurfaceControl.isValid() && !HardwareRenderer.isDrawingEnabled()) {
+            // When drawing is disabled the window layer won't have a valid buffer.
+            // Set a window crop so input can get delivered to the window.
+            mTransaction.setWindowCrop(mSurfaceControl, mSurfaceSize.x, mSurfaceSize.y).apply();
+        }
+
         mLastTransformHint = transformHint;
       
         mSurfaceControl.setTransformHint(transformHint);
@@ -8482,6 +8498,10 @@
         if (mLocalSyncState != LOCAL_SYNC_NONE) {
             writer.println(innerPrefix + "mLocalSyncState=" + mLocalSyncState);
         }
+        writer.println(innerPrefix + "mLastReportedMergedConfiguration="
+                + mLastReportedMergedConfiguration);
+        writer.println(innerPrefix + "mLastConfigurationFromResources="
+                + mLastConfigurationFromResources);
         writer.println(innerPrefix + "mIsAmbientMode="  + mIsAmbientMode);
         writer.println(innerPrefix + "mUnbufferedInputSource="
                 + Integer.toHexString(mUnbufferedInputSource));
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 218ca58..2f77901 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -777,12 +777,6 @@
     int TAKE_SCREENSHOT_FULLSCREEN = 1;
 
     /**
-     * Invoke screenshot flow allowing the user to select a region.
-     * @hide
-     */
-    int TAKE_SCREENSHOT_SELECTED_REGION = 2;
-
-    /**
      * Invoke screenshot flow with an image provided by the caller.
      * @hide
      */
@@ -794,7 +788,6 @@
      * @hide
      */
     @IntDef({TAKE_SCREENSHOT_FULLSCREEN,
-            TAKE_SCREENSHOT_SELECTED_REGION,
             TAKE_SCREENSHOT_PROVIDED_IMAGE})
     @interface ScreenshotType {}
 
diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl
index 3c7cd02..36eaf49 100644
--- a/core/java/android/window/IWindowOrganizerController.aidl
+++ b/core/java/android/window/IWindowOrganizerController.aidl
@@ -51,16 +51,19 @@
             in IWindowContainerTransactionCallback callback);
 
     /**
-     * Starts a transition.
+     * Starts a new transition.
      * @param type The transition type.
-     * @param transitionToken A token associated with the transition to start. If null, a new
-     *                        transition will be created of the provided type.
      * @param t Operations that are part of the transition.
-     * @return a token representing the transition. This will just be transitionToken if it was
-     *         non-null.
+     * @return a token representing the transition.
      */
-    IBinder startTransition(int type, in @nullable IBinder transitionToken,
-            in @nullable WindowContainerTransaction t);
+    IBinder startNewTransition(int type, in @nullable WindowContainerTransaction t);
+
+    /**
+     * Starts the given transition.
+     * @param transitionToken A token associated with the transition to start.
+     * @param t Operations that are part of the transition.
+     */
+    oneway void startTransition(IBinder transitionToken, in @nullable WindowContainerTransaction t);
 
     /**
      * Starts a legacy transition.
diff --git a/core/java/android/window/TaskFragmentParentInfo.java b/core/java/android/window/TaskFragmentParentInfo.java
index 64b2638..841354a 100644
--- a/core/java/android/window/TaskFragmentParentInfo.java
+++ b/core/java/android/window/TaskFragmentParentInfo.java
@@ -33,19 +33,19 @@
 
     private final int mDisplayId;
 
-    private final boolean mVisibleRequested;
+    private final boolean mVisible;
 
     public TaskFragmentParentInfo(@NonNull Configuration configuration, int displayId,
-            boolean visibleRequested) {
+            boolean visible) {
         mConfiguration.setTo(configuration);
         mDisplayId = displayId;
-        mVisibleRequested = visibleRequested;
+        mVisible = visible;
     }
 
     public TaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
         mConfiguration.setTo(info.getConfiguration());
         mDisplayId = info.mDisplayId;
-        mVisibleRequested = info.mVisibleRequested;
+        mVisible = info.mVisible;
     }
 
     /** The {@link Configuration} of the parent Task */
@@ -62,9 +62,9 @@
         return mDisplayId;
     }
 
-    /** Whether the parent Task is requested to be visible or not */
-    public boolean isVisibleRequested() {
-        return mVisibleRequested;
+    /** Whether the parent Task is visible or not */
+    public boolean isVisible() {
+        return mVisible;
     }
 
     /**
@@ -80,7 +80,7 @@
             return false;
         }
         return getWindowingMode() == that.getWindowingMode() && mDisplayId == that.mDisplayId
-                && mVisibleRequested == that.mVisibleRequested;
+                && mVisible == that.mVisible;
     }
 
     @WindowConfiguration.WindowingMode
@@ -93,7 +93,7 @@
         return TaskFragmentParentInfo.class.getSimpleName() + ":{"
                 + "config=" + mConfiguration
                 + ", displayId=" + mDisplayId
-                + ", visibleRequested=" + mVisibleRequested
+                + ", visible=" + mVisible
                 + "}";
     }
 
@@ -114,14 +114,14 @@
         final TaskFragmentParentInfo that = (TaskFragmentParentInfo) obj;
         return mConfiguration.equals(that.mConfiguration)
                 && mDisplayId == that.mDisplayId
-                && mVisibleRequested == that.mVisibleRequested;
+                && mVisible == that.mVisible;
     }
 
     @Override
     public int hashCode() {
         int result = mConfiguration.hashCode();
         result = 31 * result + mDisplayId;
-        result = 31 * result + (mVisibleRequested ? 1 : 0);
+        result = 31 * result + (mVisible ? 1 : 0);
         return result;
     }
 
@@ -129,13 +129,13 @@
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         mConfiguration.writeToParcel(dest, flags);
         dest.writeInt(mDisplayId);
-        dest.writeBoolean(mVisibleRequested);
+        dest.writeBoolean(mVisible);
     }
 
     private TaskFragmentParentInfo(Parcel in) {
         mConfiguration.readFromParcel(in);
         mDisplayId = in.readInt();
-        mVisibleRequested = in.readBoolean();
+        mVisible = in.readBoolean();
     }
 
     public static final Creator<TaskFragmentParentInfo> CREATOR =
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 641d1a1..fbdd325 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -132,8 +132,11 @@
      */
     public static final int FLAG_IS_BEHIND_STARTING_WINDOW = 1 << 14;
 
+    /** This change happened underneath something else. */
+    public static final int FLAG_IS_OCCLUDED = 1 << 15;
+
     /** The first unused bit. This can be used by remotes to attach custom flags to this change. */
-    public static final int FLAG_FIRST_CUSTOM = 1 << 15;
+    public static final int FLAG_FIRST_CUSTOM = 1 << 16;
 
     /** @hide */
     @IntDef(prefix = { "FLAG_" }, value = {
@@ -153,6 +156,7 @@
             FLAG_CROSS_PROFILE_OWNER_THUMBNAIL,
             FLAG_CROSS_PROFILE_WORK_THUMBNAIL,
             FLAG_IS_BEHIND_STARTING_WINDOW,
+            FLAG_IS_OCCLUDED,
             FLAG_FIRST_CUSTOM
     })
     public @interface ChangeFlags {}
@@ -362,6 +366,9 @@
         if ((flags & FLAG_IS_BEHIND_STARTING_WINDOW) != 0) {
             sb.append(sb.length() == 0 ? "" : "|").append("IS_BEHIND_STARTING_WINDOW");
         }
+        if ((flags & FLAG_IS_OCCLUDED) != 0) {
+            sb.append(sb.length() == 0 ? "" : "|").append("IS_OCCLUDED");
+        }
         if ((flags & FLAG_FIRST_CUSTOM) != 0) {
             sb.append(sb.length() == 0 ? "" : "|").append("FIRST_CUSTOM");
         }
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index 4ea5ea5..2a80d02 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -84,9 +84,8 @@
     }
 
     /**
-     * Start a transition.
+     * Starts a new transition, don't use this to start an already created one.
      * @param type The type of the transition. This is ignored if a transitionToken is provided.
-     * @param transitionToken An existing transition to start. If null, a new transition is created.
      * @param t The set of window operations that are part of this transition.
      * @return A token identifying the transition. This will be the same as transitionToken if it
      *         was provided.
@@ -94,10 +93,24 @@
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
     @NonNull
-    public IBinder startTransition(int type, @Nullable IBinder transitionToken,
+    public IBinder startNewTransition(int type, @Nullable WindowContainerTransaction t) {
+        try {
+            return getWindowOrganizerController().startNewTransition(type, t);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Starts an already created transition.
+     * @param transitionToken An existing transition to start.
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
+    public void startTransition(@NonNull IBinder transitionToken,
             @Nullable WindowContainerTransaction t) {
         try {
-            return getWindowOrganizerController().startTransition(type, transitionToken, t);
+            getWindowOrganizerController().startTransition(transitionToken, t);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 620f177..f5ba275 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1114,6 +1114,19 @@
         resolveIntent.setFlags(originalIntent.getFlags() & URI_PERMISSION_INTENT_FLAGS);
         resolveIntent.setComponent(cn);
         resolveIntent.setAction(Intent.ACTION_EDIT);
+        String originalAction = originalIntent.getAction();
+        if (Intent.ACTION_SEND.equals(originalAction)) {
+            if (resolveIntent.getData() == null) {
+                Uri uri = resolveIntent.getParcelableExtra(Intent.EXTRA_STREAM);
+                if (uri != null) {
+                    String mimeType = getContentResolver().getType(uri);
+                    resolveIntent.setDataAndType(uri, mimeType);
+                }
+            }
+        } else {
+            Log.e(TAG, originalAction + " is not supported.");
+            return null;
+        }
         final ResolveInfo ri = getPackageManager().resolveActivity(
                 resolveIntent, PackageManager.GET_META_DATA);
         if (ri == null || ri.activityInfo == null) {
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 1ec5325..4f74ca7 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -86,7 +86,6 @@
     private final ChooserActivityLogger mChooserActivityLogger;
 
     private int mNumShortcutResults = 0;
-    private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
     private boolean mApplySharingAppLimits;
 
     // Reserve spots for incoming direct share targets by adding placeholders
@@ -265,31 +264,20 @@
             return;
         }
 
-        if (!(info instanceof DisplayResolveInfo)) {
-            holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel());
-            holder.bindIcon(info);
-
-            if (info instanceof SelectableTargetInfo) {
-                // direct share targets should append the application name for a better readout
-                DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo();
-                CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : "";
-                CharSequence extendedInfo = info.getExtendedInfo();
-                String contentDescription = String.join(" ", info.getDisplayLabel(),
-                        extendedInfo != null ? extendedInfo : "", appName);
-                holder.updateContentDescription(contentDescription);
-            }
-        } else {
+        holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel());
+        holder.bindIcon(info);
+        if (info instanceof SelectableTargetInfo) {
+            // direct share targets should append the application name for a better readout
+            DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo();
+            CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : "";
+            CharSequence extendedInfo = info.getExtendedInfo();
+            String contentDescription = String.join(" ", info.getDisplayLabel(),
+                    extendedInfo != null ? extendedInfo : "", appName);
+            holder.updateContentDescription(contentDescription);
+        } else if (info instanceof DisplayResolveInfo) {
             DisplayResolveInfo dri = (DisplayResolveInfo) info;
-            holder.bindLabel(dri.getDisplayLabel(), dri.getExtendedInfo(), alwaysShowSubLabel());
-            LoadIconTask task = mIconLoaders.get(dri);
-            if (task == null) {
-                task = new LoadIconTask(dri, holder);
-                mIconLoaders.put(dri, task);
-                task.execute();
-            } else {
-                // The holder was potentially changed as the underlying items were
-                // reshuffled, so reset the target holder
-                task.setViewHolder(holder);
+            if (!dri.hasDisplayIcon()) {
+                loadIcon(dri);
             }
         }
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 0e1ed7b..c70e26f 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -55,6 +55,7 @@
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Insets;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -1475,14 +1476,21 @@
                 mMultiProfilePagerAdapter.getActiveListAdapter().mDisplayList.get(0);
         boolean inWorkProfile = getCurrentProfile() == PROFILE_WORK;
 
-        ResolverListAdapter inactiveAdapter = mMultiProfilePagerAdapter.getInactiveListAdapter();
-        DisplayResolveInfo otherProfileResolveInfo = inactiveAdapter.mDisplayList.get(0);
+        final ResolverListAdapter inactiveAdapter =
+                mMultiProfilePagerAdapter.getInactiveListAdapter();
+        final DisplayResolveInfo otherProfileResolveInfo = inactiveAdapter.mDisplayList.get(0);
 
         // Load the icon asynchronously
         ImageView icon = findViewById(R.id.icon);
-        ResolverListAdapter.LoadIconTask iconTask = inactiveAdapter.new LoadIconTask(
-                        otherProfileResolveInfo, new ResolverListAdapter.ViewHolder(icon));
-        iconTask.execute();
+        inactiveAdapter.new LoadIconTask(otherProfileResolveInfo) {
+            @Override
+            protected void onPostExecute(Drawable drawable) {
+                if (!isDestroyed()) {
+                    otherProfileResolveInfo.setDisplayIcon(drawable);
+                    new ResolverListAdapter.ViewHolder(icon).bindIcon(otherProfileResolveInfo);
+                }
+            }
+        }.execute();
 
         ((TextView) findViewById(R.id.open_cross_profile)).setText(
                 getResources().getString(
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 66fff5c..f6075b0 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -58,7 +58,10 @@
 import com.android.internal.app.chooser.TargetInfo;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 public class ResolverListAdapter extends BaseAdapter {
     private static final String TAG = "ResolverListAdapter";
@@ -87,6 +90,8 @@
     private Runnable mPostListReadyRunnable;
     private final boolean mIsAudioCaptureDevice;
     private boolean mIsTabLoaded;
+    private final Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
+    private final Map<DisplayResolveInfo, LoadLabelTask> mLabelLoaders = new HashMap<>();
 
     public ResolverListAdapter(Context context, List<Intent> payloadIntents,
             Intent[] initialIntents, List<ResolveInfo> rList,
@@ -636,26 +641,47 @@
         if (info == null) {
             holder.icon.setImageDrawable(
                     mContext.getDrawable(R.drawable.resolver_icon_placeholder));
+            holder.bindLabel("", "", false);
             return;
         }
 
-        if (info instanceof DisplayResolveInfo
-                && !((DisplayResolveInfo) info).hasDisplayLabel()) {
-            getLoadLabelTask((DisplayResolveInfo) info, holder).execute();
-        } else {
-            holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel());
-        }
-
-        if (info instanceof DisplayResolveInfo
-                && !((DisplayResolveInfo) info).hasDisplayIcon()) {
-            new LoadIconTask((DisplayResolveInfo) info, holder).execute();
-        } else {
+        if (info instanceof DisplayResolveInfo) {
+            DisplayResolveInfo dri = (DisplayResolveInfo) info;
+            boolean hasLabel = dri.hasDisplayLabel();
+            holder.bindLabel(
+                    dri.getDisplayLabel(),
+                    dri.getExtendedInfo(),
+                    hasLabel && alwaysShowSubLabel());
             holder.bindIcon(info);
+            if (!hasLabel) {
+                loadLabel(dri);
+            }
+            if (!dri.hasDisplayIcon()) {
+                loadIcon(dri);
+            }
         }
     }
 
-    protected LoadLabelTask getLoadLabelTask(DisplayResolveInfo info, ViewHolder holder) {
-        return new LoadLabelTask(info, holder);
+    protected final void loadIcon(DisplayResolveInfo info) {
+        LoadIconTask task = mIconLoaders.get(info);
+        if (task == null) {
+            task = new LoadIconTask((DisplayResolveInfo) info);
+            mIconLoaders.put(info, task);
+            task.execute();
+        }
+    }
+
+    private void loadLabel(DisplayResolveInfo info) {
+        LoadLabelTask task = mLabelLoaders.get(info);
+        if (task == null) {
+            task = createLoadLabelTask(info);
+            mLabelLoaders.put(info, task);
+            task.execute();
+        }
+    }
+
+    protected LoadLabelTask createLoadLabelTask(DisplayResolveInfo info) {
+        return new LoadLabelTask(info);
     }
 
     public void onDestroy() {
@@ -666,6 +692,16 @@
         if (mResolverListController != null) {
             mResolverListController.destroy();
         }
+        cancelTasks(mIconLoaders.values());
+        cancelTasks(mLabelLoaders.values());
+        mIconLoaders.clear();
+        mLabelLoaders.clear();
+    }
+
+    private <T extends AsyncTask> void cancelTasks(Collection<T> tasks) {
+        for (T task: tasks) {
+            task.cancel(false);
+        }
     }
 
     private static ColorMatrixColorFilter getSuspendedColorMatrix() {
@@ -883,11 +919,9 @@
 
     protected class LoadLabelTask extends AsyncTask<Void, Void, CharSequence[]> {
         private final DisplayResolveInfo mDisplayResolveInfo;
-        private final ViewHolder mHolder;
 
-        protected LoadLabelTask(DisplayResolveInfo dri, ViewHolder holder) {
+        protected LoadLabelTask(DisplayResolveInfo dri) {
             mDisplayResolveInfo = dri;
-            mHolder = holder;
         }
 
         @Override
@@ -925,21 +959,22 @@
 
         @Override
         protected void onPostExecute(CharSequence[] result) {
+            if (mDisplayResolveInfo.hasDisplayLabel()) {
+                return;
+            }
             mDisplayResolveInfo.setDisplayLabel(result[0]);
             mDisplayResolveInfo.setExtendedInfo(result[1]);
-            mHolder.bindLabel(result[0], result[1], alwaysShowSubLabel());
+            notifyDataSetChanged();
         }
     }
 
     class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
         protected final DisplayResolveInfo mDisplayResolveInfo;
         private final ResolveInfo mResolveInfo;
-        private ViewHolder mHolder;
 
-        LoadIconTask(DisplayResolveInfo dri, ViewHolder holder) {
+        LoadIconTask(DisplayResolveInfo dri) {
             mDisplayResolveInfo = dri;
             mResolveInfo = dri.getResolveInfo();
-            mHolder = holder;
         }
 
         @Override
@@ -953,17 +988,9 @@
                 mResolverListCommunicator.updateProfileViewButton();
             } else if (!mDisplayResolveInfo.hasDisplayIcon()) {
                 mDisplayResolveInfo.setDisplayIcon(d);
-                mHolder.bindIcon(mDisplayResolveInfo);
-                // Notify in case view is already bound to resolve the race conditions on
-                // low end devices
                 notifyDataSetChanged();
             }
         }
-
-        public void setViewHolder(ViewHolder holder) {
-            mHolder = holder;
-            mHolder.bindIcon(mDisplayResolveInfo);
-        }
     }
 
     /**
diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
index 5f4a9cd..473134e 100644
--- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java
@@ -172,14 +172,14 @@
 
     @Override
     public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
-        prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
+        TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
         activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
         return true;
     }
 
     @Override
     public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
-        prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
+        TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
         activity.startActivityAsUser(mResolvedIntent, options, user);
         return false;
     }
@@ -224,13 +224,6 @@
         }
     };
 
-    private static void prepareIntentForCrossProfileLaunch(Intent intent, int targetUserId) {
-        final int currentUserId = UserHandle.myUserId();
-        if (targetUserId != currentUserId) {
-            intent.fixUris(currentUserId);
-        }
-    }
-
     private DisplayResolveInfo(Parcel in) {
         mDisplayLabel = in.readCharSequence();
         mExtendedInfo = in.readCharSequence();
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 264e4f7..4b9b7cb 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -232,6 +232,7 @@
         }
         intent.setComponent(mChooserTarget.getComponentName());
         intent.putExtras(mChooserTarget.getIntentExtras());
+        TargetInfo.prepareIntentForCrossProfileLaunch(intent, userId);
 
         // Important: we will ignore the target security checks in ActivityManager
         // if and only if the ChooserTarget's target package is the same package
diff --git a/core/java/com/android/internal/app/chooser/TargetInfo.java b/core/java/com/android/internal/app/chooser/TargetInfo.java
index f56ab17..7bb7ddc 100644
--- a/core/java/com/android/internal/app/chooser/TargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/TargetInfo.java
@@ -130,4 +130,15 @@
      * @return true if this target should be pinned to the front by the request of the user
      */
     boolean isPinned();
+
+    /**
+     * Fix the URIs in {@code intent} if cross-profile sharing is required. This should be called
+     * before launching the intent as another user.
+     */
+    static void prepareIntentForCrossProfileLaunch(Intent intent, int targetUserId) {
+        final int currentUserId = UserHandle.myUserId();
+        if (targetUserId != currentUserId) {
+            intent.fixUris(currentUserId);
+        }
+    }
 }
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index 627631a..d503904 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -115,7 +115,7 @@
             Slog.i(TAG, "Setting initial brightness to default value of: " + defaultBrightness);
         }
 
-        mBrightnessSyncObserver.startObserving();
+        mBrightnessSyncObserver.startObserving(mHandler);
         mHandler.sendEmptyMessageAtTime(MSG_RUN_UPDATE, mClock.uptimeMillis());
     }
 
@@ -482,30 +482,31 @@
             }
         };
 
-        private final ContentObserver mContentObserver = new ContentObserver(mHandler) {
-            @Override
-            public void onChange(boolean selfChange, Uri uri) {
-                if (selfChange) {
-                    return;
+        private ContentObserver createBrightnessContentObserver(Handler handler) {
+            return new ContentObserver(handler) {
+                @Override
+                public void onChange(boolean selfChange, Uri uri) {
+                    if (selfChange) {
+                        return;
+                    }
+                    if (BRIGHTNESS_URI.equals(uri)) {
+                        handleBrightnessChangeInt(getScreenBrightnessInt());
+                    }
                 }
-                if (BRIGHTNESS_URI.equals(uri)) {
-                    handleBrightnessChangeInt(getScreenBrightnessInt());
-                }
-            }
-        };
+            };
+        }
 
         boolean isObserving() {
             return mIsObserving;
         }
 
-        void startObserving() {
+        void startObserving(Handler handler) {
             final ContentResolver cr = mContext.getContentResolver();
-            cr.registerContentObserver(BRIGHTNESS_URI, false, mContentObserver,
-                    UserHandle.USER_ALL);
-            mDisplayManager.registerDisplayListener(mListener, mHandler,
+            cr.registerContentObserver(BRIGHTNESS_URI, false,
+                    createBrightnessContentObserver(handler), UserHandle.USER_ALL);
+            mDisplayManager.registerDisplayListener(mListener, handler,
                     DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
             mIsObserving = true;
         }
-
     }
 }
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 708713b..5de7240 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -439,6 +439,22 @@
     @VisibleForTesting
     public FrameTracker createFrameTracker(Configuration config, Session session) {
         final View view = config.mView;
+
+        if (!config.hasValidView()) {
+            boolean attached = false;
+            boolean hasViewRoot = false;
+            boolean hasRenderer = false;
+            if (view != null) {
+                attached = view.isAttachedToWindow();
+                hasViewRoot = view.getViewRootImpl() != null;
+                hasRenderer = view.getThreadedRenderer() != null;
+            }
+            Log.d(TAG, "create FrameTracker fails: view=" + view
+                    + ", attached=" + attached + ", hasViewRoot=" + hasViewRoot
+                    + ", hasRenderer=" + hasRenderer, new Throwable());
+            return null;
+        }
+
         final ThreadedRendererWrapper threadedRenderer =
                 view == null ? null : new ThreadedRendererWrapper(view.getThreadedRenderer());
         final ViewRootWrapper viewRoot =
@@ -545,6 +561,7 @@
 
         // begin a new trace session.
         tracker = createFrameTracker(conf, new Session(cujType, conf.mTag));
+        if (tracker == null) return false;
         putTracker(cujType, tracker);
         tracker.begin();
 
@@ -1066,9 +1083,19 @@
                     msg.append("Must pass in a valid surface control if only instrument surface; ");
                 }
             } else {
-                if (mView == null || !mView.isAttachedToWindow()) {
+                if (!hasValidView()) {
                     shouldThrow = true;
-                    msg.append("Null view or unattached view while instrumenting view; ");
+                    boolean attached = false;
+                    boolean hasViewRoot = false;
+                    boolean hasRenderer = false;
+                    if (mView != null) {
+                        attached = mView.isAttachedToWindow();
+                        hasViewRoot = mView.getViewRootImpl() != null;
+                        hasRenderer = mView.getThreadedRenderer() != null;
+                    }
+                    String err = "invalid view: view=" + mView + ", attached=" + attached
+                            + ", hasViewRoot=" + hasViewRoot + ", hasRenderer=" + hasRenderer;
+                    msg.append(err);
                 }
             }
             if (shouldThrow) {
@@ -1076,6 +1103,12 @@
             }
         }
 
+        boolean hasValidView() {
+            return mSurfaceOnly
+                    || (mView != null && mView.isAttachedToWindow()
+                    && mView.getViewRootImpl() != null && mView.getThreadedRenderer() != null);
+        }
+
         /**
          * @return true if only instrumenting surface, false otherwise
          */
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index ec2bc7c..8b96597 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -167,7 +167,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    static final int VERSION = 208;
+    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
@@ -6145,12 +6145,13 @@
 
     @UnsupportedAppUsage
     @GuardedBy("this")
-    public void noteUserActivityLocked(int uid, int event) {
+    public void noteUserActivityLocked(int uid, @PowerManager.UserActivityEvent int event) {
         noteUserActivityLocked(uid, event, mClock.elapsedRealtime(), mClock.uptimeMillis());
     }
 
     @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);
@@ -9962,14 +9963,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());
             }
         }
diff --git a/core/java/com/android/internal/util/ObservableServiceConnection.java b/core/java/com/android/internal/util/ObservableServiceConnection.java
new file mode 100644
index 0000000..3165d29
--- /dev/null
+++ b/core/java/com/android/internal/util/ObservableServiceConnection.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.CallbackRegistry.NotifierCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * {@link ObservableServiceConnection} is a concrete implementation of {@link ServiceConnection}
+ * that enables monitoring the status of a binder connection. It also aides in automatically
+ * converting a proxy into an internal wrapper type.
+ *
+ * @param <T> The type of the wrapper over the resulting service.
+ */
+public class ObservableServiceConnection<T> implements ServiceConnection {
+    /**
+     * An interface for converting the service proxy into a given internal wrapper type.
+     *
+     * @param <T> The type of the wrapper over the resulting service.
+     */
+    public interface ServiceTransformer<T> {
+        /**
+         * Called to convert the service proxy to the wrapper type.
+         *
+         * @param service The service proxy to create the wrapper type from.
+         * @return The wrapper type.
+         */
+        T convert(IBinder service);
+    }
+
+    /**
+     * An interface for listening to the connection status.
+     *
+     * @param <T> The wrapper type.
+     */
+    public interface Callback<T> {
+        /**
+         * Invoked when the service has been successfully connected to.
+         *
+         * @param connection The {@link ObservableServiceConnection} instance that is now connected
+         * @param service    The service proxy converted into the typed wrapper.
+         */
+        void onConnected(ObservableServiceConnection<T> connection, T service);
+
+        /**
+         * Invoked when the service has been disconnected.
+         *
+         * @param connection The {@link ObservableServiceConnection} that is now disconnected.
+         * @param reason     The reason for the disconnection.
+         */
+        void onDisconnected(ObservableServiceConnection<T> connection,
+                @DisconnectReason int reason);
+    }
+
+    /**
+     * Default state, service has not yet disconnected.
+     */
+    public static final int DISCONNECT_REASON_NONE = 0;
+    /**
+     * Disconnection was due to the resulting binding being {@code null}.
+     */
+    public static final int DISCONNECT_REASON_NULL_BINDING = 1;
+    /**
+     * Disconnection was due to the remote end disconnecting.
+     */
+    public static final int DISCONNECT_REASON_DISCONNECTED = 2;
+    /**
+     * Disconnection due to the binder dying.
+     */
+    public static final int DISCONNECT_REASON_BINDING_DIED = 3;
+    /**
+     * Disconnection from an explicit unbinding.
+     */
+    public static final int DISCONNECT_REASON_UNBIND = 4;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            DISCONNECT_REASON_NONE,
+            DISCONNECT_REASON_NULL_BINDING,
+            DISCONNECT_REASON_DISCONNECTED,
+            DISCONNECT_REASON_BINDING_DIED,
+            DISCONNECT_REASON_UNBIND
+    })
+    public @interface DisconnectReason {
+    }
+
+    private final Object mLock = new Object();
+    private final Context mContext;
+    private final Executor mExecutor;
+    private final ServiceTransformer<T> mTransformer;
+    private final Intent mServiceIntent;
+    private final int mFlags;
+
+    @GuardedBy("mLock")
+    private T mService;
+    @GuardedBy("mLock")
+    private boolean mBoundCalled = false;
+    @GuardedBy("mLock")
+    private int mLastDisconnectReason = DISCONNECT_REASON_NONE;
+
+    private final CallbackRegistry<Callback<T>, ObservableServiceConnection<T>, T>
+            mCallbackRegistry = new CallbackRegistry<>(
+            new NotifierCallback<Callback<T>, ObservableServiceConnection<T>, T>() {
+                    @Override
+                    public void onNotifyCallback(Callback<T> callback,
+                            ObservableServiceConnection<T> sender,
+                            int disconnectReason, T service) {
+                        mExecutor.execute(() -> {
+                            synchronized (mLock) {
+                                if (service != null) {
+                                    callback.onConnected(sender, service);
+                                } else if (mLastDisconnectReason != DISCONNECT_REASON_NONE) {
+                                    callback.onDisconnected(sender, disconnectReason);
+                                }
+                            }
+                        });
+                    }
+                });
+
+    /**
+     * Default constructor for {@link ObservableServiceConnection}.
+     *
+     * @param context     The context from which the service will be bound with.
+     * @param executor    The executor for connection callbacks to be delivered on
+     * @param transformer A {@link ObservableServiceConnection.ServiceTransformer} for transforming
+     *                    the resulting service into a desired type.
+     */
+    public ObservableServiceConnection(@NonNull Context context,
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull ServiceTransformer<T> transformer,
+            Intent serviceIntent,
+            int flags) {
+        mContext = context;
+        mExecutor = executor;
+        mTransformer = transformer;
+        mServiceIntent = serviceIntent;
+        mFlags = flags;
+    }
+
+    /**
+     * Initiate binding to the service.
+     *
+     * @return {@code true} if initiating binding succeed, {@code false} if the binding failed or
+     * if this service is already bound. Regardless of the return value, you should later call
+     * {@link #unbind()} to release the connection.
+     */
+    public boolean bind() {
+        synchronized (mLock) {
+            if (mBoundCalled) {
+                return false;
+            }
+            final boolean bindResult =
+                    mContext.bindService(mServiceIntent, mFlags, mExecutor, this);
+            mBoundCalled = true;
+            return bindResult;
+        }
+    }
+
+    /**
+     * Disconnect from the service if bound.
+     */
+    public void unbind() {
+        onDisconnected(DISCONNECT_REASON_UNBIND);
+    }
+
+    /**
+     * Adds a callback for receiving connection updates.
+     *
+     * @param callback The {@link Callback} to receive future updates.
+     */
+    public void addCallback(Callback<T> callback) {
+        mCallbackRegistry.add(callback);
+        mExecutor.execute(() -> {
+            synchronized (mLock) {
+                if (mService != null) {
+                    callback.onConnected(this, mService);
+                } else if (mLastDisconnectReason != DISCONNECT_REASON_NONE) {
+                    callback.onDisconnected(this, mLastDisconnectReason);
+                }
+            }
+        });
+    }
+
+    /**
+     * Removes previously added callback from receiving future connection updates.
+     *
+     * @param callback The {@link Callback} to be removed.
+     */
+    public void removeCallback(Callback<T> callback) {
+        synchronized (mLock) {
+            mCallbackRegistry.remove(callback);
+        }
+    }
+
+    private void onDisconnected(@DisconnectReason int reason) {
+        synchronized (mLock) {
+            if (!mBoundCalled) {
+                return;
+            }
+            mBoundCalled = false;
+            mLastDisconnectReason = reason;
+            mContext.unbindService(this);
+            mService = null;
+            mCallbackRegistry.notifyCallbacks(this, reason, null);
+        }
+    }
+
+    @Override
+    public final void onServiceConnected(ComponentName name, IBinder service) {
+        synchronized (mLock) {
+            mService = mTransformer.convert(service);
+            mLastDisconnectReason = DISCONNECT_REASON_NONE;
+            mCallbackRegistry.notifyCallbacks(this, mLastDisconnectReason, mService);
+        }
+    }
+
+    @Override
+    public final void onServiceDisconnected(ComponentName name) {
+        onDisconnected(DISCONNECT_REASON_DISCONNECTED);
+    }
+
+    @Override
+    public final void onBindingDied(ComponentName name) {
+        onDisconnected(DISCONNECT_REASON_BINDING_DIED);
+    }
+
+    @Override
+    public final void onNullBinding(ComponentName name) {
+        onDisconnected(DISCONNECT_REASON_NULL_BINDING);
+    }
+}
diff --git a/core/java/com/android/internal/util/PersistentServiceConnection.java b/core/java/com/android/internal/util/PersistentServiceConnection.java
new file mode 100644
index 0000000..d201734
--- /dev/null
+++ b/core/java/com/android/internal/util/PersistentServiceConnection.java
@@ -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.internal.util;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.SystemClock;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.Executor;
+
+/**
+ * {@link PersistentServiceConnection} is a concrete implementation of {@link ServiceConnection}
+ * that maintains the binder connection by handling reconnection when a failure occurs.
+ *
+ * @param <T> The transformed connection type handled by the service.
+ *
+ * When the target process is killed (by OOM-killer, force-stopped, crash, etc..) then this class
+ * will trigger a reconnection to the target. This should be used carefully.
+ *
+ * NOTE: This class does *not* handle package-updates -- i.e. even if the binding dies due to
+ * the target package being updated, this class won't reconnect.  This is because this class doesn't
+ * know what to do when the service component has gone missing, for example.  If the user of this
+ * class wants to restore the connection, then it should call {@link #unbind()} and {@link #bind}
+ * explicitly.
+ */
+public class PersistentServiceConnection<T> extends ObservableServiceConnection<T> {
+    private final Callback<T> mConnectionCallback = new Callback<T>() {
+        private long mConnectedTime;
+
+        @Override
+        public void onConnected(ObservableServiceConnection<T> connection, T service) {
+            mConnectedTime = mInjector.uptimeMillis();
+        }
+
+        @Override
+        public void onDisconnected(ObservableServiceConnection<T> connection,
+                @DisconnectReason int reason) {
+            if (reason == DISCONNECT_REASON_UNBIND) return;
+            synchronized (mLock) {
+                if ((mInjector.uptimeMillis() - mConnectedTime) > mMinConnectionDurationMs) {
+                    mReconnectAttempts = 0;
+                    bindInternalLocked();
+                } else {
+                    scheduleConnectionAttemptLocked();
+                }
+            }
+        }
+    };
+
+    private final Object mLock = new Object();
+    private final Injector mInjector;
+    private final Handler mHandler;
+    private final int mMinConnectionDurationMs;
+    private final int mMaxReconnectAttempts;
+    private final int mBaseReconnectDelayMs;
+    @GuardedBy("mLock")
+    private int mReconnectAttempts;
+    @GuardedBy("mLock")
+    private Object mCancelToken;
+
+    private final Runnable mConnectRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mLock) {
+                mCancelToken = null;
+                bindInternalLocked();
+            }
+        }
+    };
+
+    /**
+     * Default constructor for {@link PersistentServiceConnection}.
+     *
+     * @param context     The context from which the service will be bound with.
+     * @param executor    The executor for connection callbacks to be delivered on
+     * @param transformer A {@link ServiceTransformer} for transforming
+     */
+    public PersistentServiceConnection(Context context,
+            Executor executor,
+            Handler handler,
+            ServiceTransformer<T> transformer,
+            Intent serviceIntent,
+            int flags,
+            int minConnectionDurationMs,
+            int maxReconnectAttempts,
+            int baseReconnectDelayMs) {
+        this(context,
+                executor,
+                handler,
+                transformer,
+                serviceIntent,
+                flags,
+                minConnectionDurationMs,
+                maxReconnectAttempts,
+                baseReconnectDelayMs,
+                new Injector());
+    }
+
+    @VisibleForTesting
+    public PersistentServiceConnection(
+            Context context,
+            Executor executor,
+            Handler handler,
+            ServiceTransformer<T> transformer,
+            Intent serviceIntent,
+            int flags,
+            int minConnectionDurationMs,
+            int maxReconnectAttempts,
+            int baseReconnectDelayMs,
+            Injector injector) {
+        super(context, executor, transformer, serviceIntent, flags);
+        mHandler = handler;
+        mMinConnectionDurationMs = minConnectionDurationMs;
+        mMaxReconnectAttempts = maxReconnectAttempts;
+        mBaseReconnectDelayMs = baseReconnectDelayMs;
+        mInjector = injector;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean bind() {
+        synchronized (mLock) {
+            addCallback(mConnectionCallback);
+            mReconnectAttempts = 0;
+            return bindInternalLocked();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private boolean bindInternalLocked() {
+        return super.bind();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void unbind() {
+        synchronized (mLock) {
+            removeCallback(mConnectionCallback);
+            cancelPendingConnectionAttemptLocked();
+            super.unbind();
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void cancelPendingConnectionAttemptLocked() {
+        if (mCancelToken != null) {
+            mHandler.removeCallbacksAndMessages(mCancelToken);
+            mCancelToken = null;
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void scheduleConnectionAttemptLocked() {
+        cancelPendingConnectionAttemptLocked();
+
+        if (mReconnectAttempts >= mMaxReconnectAttempts) {
+            return;
+        }
+
+        final long reconnectDelayMs =
+                (long) Math.scalb(mBaseReconnectDelayMs, mReconnectAttempts);
+
+        mCancelToken = new Object();
+        mHandler.postDelayed(mConnectRunnable, mCancelToken, reconnectDelayMs);
+        mReconnectAttempts++;
+    }
+
+    /**
+     * Injector for testing
+     */
+    @VisibleForTesting
+    public static class Injector {
+        /**
+         * Returns milliseconds since boot, not counting time spent in deep sleep. Can be overridden
+         * in tests with a fake clock.
+         */
+        public long uptimeMillis() {
+            return SystemClock.uptimeMillis();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a4da8de4..1235b60 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1522,8 +1522,7 @@
                         STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
                         STRONG_AUTH_REQUIRED_AFTER_TIMEOUT,
                         STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN,
-                        STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT,
-                        SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED})
+                        STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1576,12 +1575,6 @@
         public static final int STRONG_AUTH_REQUIRED_AFTER_NON_STRONG_BIOMETRICS_TIMEOUT = 0x80;
 
         /**
-         * Some authentication is required because the trustagent either timed out or was disabled
-         * manually.
-         */
-        public static final int SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED = 0x100;
-
-        /**
          * Strong auth flags that do not prevent biometric methods from being accepted as auth.
          * If any other flags are set, biometric authentication is disabled.
          */
diff --git a/core/proto/android/os/processstarttime.proto b/core/proto/android/os/processstarttime.proto
deleted file mode 100644
index d0f8bae..0000000
--- a/core/proto/android/os/processstarttime.proto
+++ /dev/null
@@ -1,92 +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.
- */
-
-syntax = "proto2";
-package android.os;
-
-option java_multiple_files = true;
-
-// This message is used for statsd logging and should be kept in sync with
-// frameworks/proto_logging/stats/atoms.proto
-/**
- * Logs information about process start time.
- *
- * Logged from:
- *      frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
- */
-message ProcessStartTime {
-  // The uid of the ProcessRecord.
-  optional int32 uid = 1;
-
-  // The process pid.
-  optional int32 pid = 2;
-
-  // The process name.
-  // Usually package name, "system" for system server.
-  // Provided by ActivityManagerService.
-  optional string process_name = 3;
-
-  enum StartType {
-    UNKNOWN = 0;
-    WARM = 1;
-    HOT = 2;
-    COLD = 3;
-  }
-
-  // The start type.
-  optional StartType type = 4;
-
-  // The elapsed realtime at the start of the process.
-  optional int64 process_start_time_millis = 5;
-
-  // Number of milliseconds it takes to reach bind application.
-  optional int32 bind_application_delay_millis = 6;
-
-  // Number of milliseconds it takes to finish start of the process.
-  optional int32 process_start_delay_millis = 7;
-
-  // hostingType field in ProcessRecord, the component type such as "activity",
-  // "service", "content provider", "broadcast" or other strings.
-  optional string hosting_type = 8;
-
-  // hostingNameStr field in ProcessRecord. The component class name that runs
-  // in this process.
-  optional string hosting_name = 9;
-
-  // Broadcast action name.
-  optional string broadcast_action_name = 10;
-
-  enum HostingTypeId {
-    HOSTING_TYPE_UNKNOWN = 0;
-    HOSTING_TYPE_ACTIVITY = 1;
-    HOSTING_TYPE_ADDED_APPLICATION = 2;
-    HOSTING_TYPE_BACKUP = 3;
-    HOSTING_TYPE_BROADCAST = 4;
-    HOSTING_TYPE_CONTENT_PROVIDER = 5;
-    HOSTING_TYPE_LINK_FAIL = 6;
-    HOSTING_TYPE_ON_HOLD = 7;
-    HOSTING_TYPE_NEXT_ACTIVITY = 8;
-    HOSTING_TYPE_NEXT_TOP_ACTIVITY = 9;
-    HOSTING_TYPE_RESTART = 10;
-    HOSTING_TYPE_SERVICE = 11;
-    HOSTING_TYPE_SYSTEM = 12;
-    HOSTING_TYPE_TOP_ACTIVITY = 13;
-    HOSTING_TYPE_EMPTY = 14;
-  }
-
-  optional HostingTypeId hosting_type_id = 11;
-}
-
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 0a52687..8fb09fc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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\nHierdie program het steeds toegang tot eie loglêers as jy nie vir hierdie program toegang tot alle toestelloglêers gee nie. Jou toestelvervaardiger het dalk steeds toegang tot sommige loglêers of inligting op jou toestel.\n\nKom meer te wete by g.co/android/devicelogs."</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 01565f2..7c439008 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"የመሣሪያ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ምን እንደሚከሰት ይመዘግባሉ። መተግበሪያዎች ችግሮችን ለማግኘት እና ለማስተካከል እነዚህን ምዝግብ ማስታወሻዎች መጠቀም ይችላሉ።\n\nአንዳንድ ምዝግብ ማስታወሻዎች ሚስጥራዊነት ያለው መረጃ ሊይዙ ይችላሉ፣ ስለዚህ የሚያምኗቸውን መተግበሪያዎች ብቻ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርሱ ይፍቀዱላቸው። \n\nይህ መተግበሪያ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ካልፈቀዱለት አሁንም የራሱን ምዝግብ ማስታወሻዎች መድረስ ይችላል። የእርስዎ መሣሪያ አምራች አሁንም አንዳንድ ምዝግብ ማስታወሻዎችን ወይም መረጃዎችን በመሣሪያዎ ላይ ሊደርስ ይችላል።"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"የመሣሪያ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ምን እንደሚከሰት ይመዘግባሉ። መተግበሪያዎች ችግሮችን ለማግኘት እና ለማስተካከል እነዚህን ምዝግብ ማስታወሻዎች መጠቀም ይችላሉ።\n\nአንዳንድ ምዝግብ ማስታወሻዎች ሚስጥራዊነት ያለው መረጃ ሊይዙ ይችላሉ፣ ስለዚህ የሚያምኗቸውን መተግበሪያዎች ብቻ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርሱ ይፍቀዱላቸው። \n\nይህ መተግበሪያ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ካልፈቀዱለት አሁንም የራሱን ምዝግብ ማስታወሻዎች መድረስ ይችላል። የእርስዎ መሣሪያ አምራች አሁንም አንዳንድ ምዝግብ ማስታወሻዎችን ወይም መረጃዎችን በመሣሪያዎ ላይ ሊደርስ ይችላል።"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"የመሣሪያ ምዝግብ ማስታወሻዎች በመሣሪያዎ ላይ ምን እንደሚከሰት ይመዘግባሉ። መተግበሪያዎች ችግሮችን ለማግኘት እና ለማስተካከል እነዚህን ምዝግብ ማስታወሻዎች መጠቀም ይችላሉ።\n\nአንዳንድ ምዝግብ ማስታወሻዎች ሚስጥራዊነት ያለው መረጃ ሊይዙ ይችላሉ፣ ስለዚህ የሚያምኗቸው መተግበሪያዎች ብቻ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርሱ ይፍቀዱላቸው። \n\nይህ መተግበሪያ ሁሉንም የመሣሪያ ምዝግብ ማስታወሻዎች እንዲደርስ ካልፈቀዱለት አሁንም የራሱን ምዝግብ ማስታወሻዎች መድረስ ይችላል። የመሣሪያዎ አምራች አሁንም አንዳንድ ምዝግብ ማስታወሻዎችን ወይም መረጃዎችን በመሣሪያዎ ላይ ሊደርስ ይችላል።\n\ng.co/android/devicelogs ላይ የበለጠ ይወቁ።"</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-ar/strings.xml b/core/res/res/values-ar/strings.xml
index c990850..1280485 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -2054,7 +2054,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ترصد سجلّات الجهاز ما يحدث على جهازك. يمكن أن تستخدم التطبيقات هذه السجلّات لتحديد المشاكل وحلها.\n\nقد تحتوي بعض السجلّات على معلومات حساسة، ولذلك يجب عدم السماح بالوصول إلى جميع سجلّات الجهاز إلا للتطبيقات التي تثق بها. \n\nإذا لم تسمح بوصول هذا التطبيق إلى جميع سجلّات الجهاز، يظل بإمكان التطبيق الوصول إلى سجلّاته. ويظل بإمكان الشركة المصنِّعة لجهازك الوصول إلى بعض السجلّات أو المعلومات المتوفّرة على جهازك."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ترصد سجلّات الجهاز ما يحدث على جهازك. يمكن أن تستخدم التطبيقات هذه السجلّات لتحديد المشاكل وحلها.\n\nقد تحتوي بعض السجلّات على معلومات حساسة، ولذلك يجب عدم السماح بالوصول إلى جميع سجلّات الجهاز إلا للتطبيقات التي تثق بها. \n\nإذا لم تسمح بوصول هذا التطبيق إلى جميع سجلّات الجهاز، يظل بإمكان التطبيق الوصول إلى سجلّاته. ويظل بإمكان الشركة المصنِّعة لجهازك الوصول إلى بعض السجلّات أو المعلومات المتوفّرة على جهازك."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"‏ترصد سجلّات الجهاز ما يحدث على جهازك. يمكن أن تستخدم التطبيقات هذه السجلّات لتحديد المشاكل وحلّها.\n\nقد تحتوي بعض السجلّات على معلومات حساسة، ولذلك يجب عدم السماح بالوصول إلى جميع سجلّات الجهاز إلا للتطبيقات التي تثق بها. \n\nإذا لم تسمح بوصول هذا التطبيق إلى جميع سجلّات الجهاز، يظل بإمكان التطبيق الوصول إلى سجلّاته. وقد يظل بإمكان الشركة المصنِّعة لجهازك الوصول إلى بعض السجلّات أو المعلومات المتوفّرة على جهازك.\n\nتعرَّف على مزيد من المعلومات على الرابط g.co/android/devicelogs."</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-as/strings.xml b/core/res/res/values-as/strings.xml
index 6dae3ca..c9550c8 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -437,8 +437,8 @@
     <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>
-    <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"অতিৰিক্ত অৱস্থান দেখুওৱা নির্দেশত প্ৰৱেশ কৰক"</string>
-    <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"অৱস্থানৰ অতিৰিক্ত নির্দেশনাসমূহত প্ৰৱেশ কৰিবলৈ এপক অনুমতি দিয়ে। ইয়ে এপটোক জিপিএছ বা অন্য অৱস্থান উৎসসমূহৰ কাৰ্যকলাপত হস্তক্ষেপ কৰাৰ সুযোগ দিব পাৰে।"</string>
+    <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"অতিৰিক্ত অৱস্থান প্ৰদানকাৰী নির্দেশসমূহ এক্সেছ কৰে"</string>
+    <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"অৱস্থানৰ অতিৰিক্ত নির্দেশনাসমূহ এক্সেছ কৰিবলৈ এপক অনুমতি দিয়ে। ই এপ্‌টোক জিপিএছ বা অন্য অৱস্থান উৎসসমূহৰ কাৰ্যকলাপত হস্তক্ষেপ কৰাৰ সুযোগ দিব পাৰে।"</string>
     <string name="permlab_accessFineLocation" msgid="6426318438195622966">"কেৱল অগ্ৰভূমিত অৱস্থানৰ সঠিক তথ্য পাওক"</string>
     <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"এই এপ্‌টো ব্যৱহাৰ হৈ থকা অৱস্থাত ই অৱস্থান সেৱাসমূহৰ পৰা আপোনাৰ সঠিক অৱস্থান লাভ কৰিব পাৰে। এপ্‌টোৱে অৱস্থান লাভ কৰিবলৈ হ’লে আপোনাৰ ডিভাইচৰ অৱস্থান সেৱাসমূহ অন কৰি ৰাখিবই লাগিব। ইয়াৰ ফলত বেটাৰীৰ ব্যৱহাৰ বাঢ়িব পাৰে।"</string>
     <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"কেৱল অগ্ৰভূমিত আনুমানিক অৱস্থান এক্সেছ কৰক"</string>
@@ -722,7 +722,7 @@
     <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"এপটোক নেটৱৰ্ক সংযোগৰ নীতিসমূহ পৰিচালনা কৰিবলৈ আৰু এপ্-বিশেষ নিয়ম সংজ্ঞাবদ্ধ কৰিবলৈ অনুমতি দিয়ে।"</string>
     <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"নেটৱর্ক ব্যৱহাৰৰ হিচাপ সলনি কৰক"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"এপ অনুসুৰি নেটৱর্কৰ ব্যৱহাৰৰ হিচাপ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। এয়া সাধাৰণ এপবোৰৰ ব্যৱহাৰৰ বাবে নহয়।"</string>
-    <string name="permlab_accessNotifications" msgid="7130360248191984741">"প্ৰৱেশ জাননীসমূহ"</string>
+    <string name="permlab_accessNotifications" msgid="7130360248191984741">"জাননীসমূহ এক্সেছ কৰে"</string>
     <string name="permdesc_accessNotifications" msgid="761730149268789668">"অন্য এপসমূহৰদ্বাৰা প\'ষ্ট কৰা জাননীসমূহকে ধৰি জাননী বিচাৰি উলিয়াবলৈ, পৰীক্ষা কৰিবলৈ আৰু মচিবলৈ অনুমতি দিয়ে।"</string>
     <string name="permlab_bindNotificationListenerService" msgid="5848096702733262458">"এটা জাননী শুনা সেৱাৰ লগত সংযুক্ত হ\'ব পাৰে"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="4970553694467137126">"এটা জাননী শ্ৰৱণ সেৱা প্ৰদানকাৰীৰ শীৰ্ষ স্তৰৰ ইণ্টাৰফেইচৰ লগত সংযুক্ত হ\'বলৈ ধাৰকক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
@@ -736,7 +736,7 @@
     <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"এটা এপ্লিকেশ্বনক নেটৱৰ্ক অৱস্থাসমূহত নিৰীক্ষণৰ বাবে শুনিবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
     <string name="permlab_setInputCalibration" msgid="932069700285223434">"ইনপুট ডিভাইচ কেলিব্ৰেশ্বন সলনি কৰিব পাৰে"</string>
     <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"টাচ্চ স্ক্ৰীনৰ কেলিব্ৰেশ্বন পেৰামিটাৰ সংশোধন কৰিবলৈ এপক অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে কেতিয়াও প্ৰয়োজন হোৱা উচিত নহয়।"</string>
-    <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM প্ৰমাণপত্ৰসমূহলৈ প্ৰৱেশ"</string>
+    <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"DRM প্ৰমাণপত্ৰসমূহ এক্সেছ কৰে"</string>
     <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"এটা এপ্লিকেশ্বনক DRM প্ৰমাণপত্ৰ গোটাবলৈ আৰু ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে। সাধাৰণ এপসমূহৰ বাবে সাধাৰণতে প্ৰয়োজন নহয়।"</string>
     <string name="permlab_handoverStatus" msgid="7620438488137057281">"Android বীম স্থানান্তৰণৰ স্থিতি লাভ কৰিব পাৰে"</string>
     <string name="permdesc_handoverStatus" msgid="3842269451732571070">"বৰ্তমানৰ Android Beam স্থানান্তৰণসমূহৰ বিষয়ে তথ্য পাবলৈ এই এপ্লিকেশ্বনক অনুমতি দিয়ে"</string>
@@ -1470,7 +1470,7 @@
     <string name="ime_action_default" msgid="8265027027659800121">"কার্য কৰক"</string>
     <string name="dial_number_using" msgid="6060769078933953531">"<xliff:g id="NUMBER">%s</xliff:g> ব্যৱহাৰ কৰি \n নম্বৰটো ডায়েল কৰক"</string>
     <string name="create_contact_using" msgid="6200708808003692594">"<xliff:g id="NUMBER">%s</xliff:g> ব্যৱহাৰ কৰি সম্পৰ্ক \n সৃষ্টি কৰক"</string>
-    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"বৰ্তমান আৰু ভৱিষ্যতে আপোনাৰ একাউণ্টত প্ৰৱেশ কৰিবলৈ তলৰ এটা বা অধিক এপে অনুমতি লাভৰ বাবে অনুৰোধ কৰিছে৷"</string>
+    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"তলৰ এটা বা একাধিক এপে বৰ্তমান আৰু ভৱিষ্যতে আপোনাৰ একাউণ্ট এক্সেছ কৰিবলৈ অনুমতি বিচাৰি অনুৰোধ কৰিছে৷"</string>
     <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"আপুনি এই অনুৰোধক সন্মতি দিব বিচাৰেনে?"</string>
     <string name="grant_permissions_header_text" msgid="3420736827804657201">"ব্যৱহাৰ কৰাৰ অনুমতি বিচাৰি কৰা অনুৰোধ"</string>
     <string name="allow" msgid="6195617008611933762">"অনুমতি দিয়ক"</string>
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"আপোনাৰ ডিভাইচত কি কি ঘটে সেয়া ডিভাইচ লগে ৰেকৰ্ড কৰে। এপ্‌সমূহে সমস্যা বিচাৰিবলৈ আৰু সমাধান কৰিবলৈ এই লগসমূহ ব্যৱহাৰ কৰিব পাৰে।\n\nকিছুমান লগত সংবেদনশীল তথ্য থাকিব পাৰে, গতিকে কেৱল আপুনি বিশ্বাস কৰা এপকহে আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি দিয়ক। \n\nআপুনি যদি এই এপ্‌টোক আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি নিদিয়ে, তথাপিও ই নিজৰ লগসমূহ এক্সেছ কৰিব পাৰিব। আপোনাৰ ডিভাইচৰ নিৰ্মাতাই তথাপিও হয়তো আপোনাৰ ডিভাইচটোত থকা কিছু লগ অথবা তথ্য এক্সেছ কৰিব পাৰিব।"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"আপোনাৰ ডিভাইচত কি কি ঘটে সেয়া ডিভাইচ লগে ৰেকৰ্ড কৰে। এপ্‌সমূহে সমস্যা বিচাৰিবলৈ আৰু সমাধান কৰিবলৈ এই লগসমূহ ব্যৱহাৰ কৰিব পাৰে।\n\nকিছুমান লগত সংবেদনশীল তথ্য থাকিব পাৰে, গতিকে কেৱল আপুনি বিশ্বাস কৰা এপকহে আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি দিয়ক। \n\nআপুনি যদি এই এপ্‌টোক আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি নিদিয়ে, তথাপিও ই নিজৰ লগসমূহ এক্সেছ কৰিব পাৰিব। আপোনাৰ ডিভাইচৰ নিৰ্মাতাই তথাপিও হয়তো আপোনাৰ ডিভাইচটোত থকা কিছু লগ অথবা তথ্য এক্সেছ কৰিব পাৰিব।"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"আপোনাৰ ডিভাইচত কি কি ঘটে সেয়া ডিভাইচ লগে ৰেকৰ্ড কৰে। এপ্‌সমূহে সমস্যা বিচাৰিবলৈ আৰু সমাধান কৰিবলৈ এই লগসমূহ ব্যৱহাৰ কৰিব পাৰে।\n\nকিছুমান লগত সংবেদনশীল তথ্য থাকিব পাৰে, গতিকে কেৱল আপুনি বিশ্বাস কৰা এপকহে আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি দিয়ক। \n\nআপুনি যদি এই এপ্‌টোক আটাইবোৰ ডিভাইচ লগ এক্সেছ কৰাৰ অনুমতি নিদিয়ে, তথাপিও ই নিজৰ লগসমূহ এক্সেছ কৰিব পাৰিব। আপোনাৰ ডিভাইচৰ নিৰ্মাতাই তথাপিও হয়তো আপোনাৰ ডিভাইচটোত থকা কিছু লগ অথবা তথ্য এক্সেছ কৰিব পাৰিব।\n\ng.co/android/devicelogsত অধিক জানক।"</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-az/strings.xml b/core/res/res/values-az/strings.xml
index 2e93dcb..bc6aa16 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nƏtraflı məlumat: g.co/android/devicelogs."</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 afd6cd0..d0e2a3c 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nSaznajte više na g.co/android/devicelogs."</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 5a0021c..95968f1 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -195,7 +195,7 @@
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string>
     <string name="location_changed_notification_title" msgid="3620158742816699316">"Праграмы могуць атрымліваць даныя пра ваша месцазнаходжанне"</string>
     <string name="location_changed_notification_text" msgid="7158423339982706912">"Каб даведацца больш, звярніцеся да ІТ-адміністратара"</string>
-    <string name="geofencing_service" msgid="3826902410740315456">"Служба вызначэння геаперыметра"</string>
+    <string name="geofencing_service" msgid="3826902410740315456">"Сэрвіс геазаніравання"</string>
     <string name="country_detector" msgid="7023275114706088854">"Дэтэктар краіны"</string>
     <string name="location_service" msgid="2439187616018455546">"Служба геалакацыі"</string>
     <string name="gnss_service" msgid="8907781262179951385">"Служба GNSS"</string>
@@ -2052,7 +2052,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Журналы прылад запісваюць усё, што адбываецца на вашай прыладзе. Праграмы выкарыстоўваюць гэтыя журналы для пошуку і выпраўлення памылак.\n\nУ некаторых журналах можа ўтрымлівацца канфідэнцыяльная інфармацыя, таму давайце доступ да ўсіх журналаў прылады толькі тым праграмам, якім вы давяраеце. \n\nКалі вы не дасце гэтай праграме доступу да ўсіх журналаў прылад, у яе ўсё роўна застанецца доступ да ўласных журналаў. Для вытворцы вашай прылады будуць даступнымі некаторыя журналы і інфармацыя на вашай прыладзе."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Журналы прылад запісваюць усё, што адбываецца на вашай прыладзе. Праграмы выкарыстоўваюць гэтыя журналы для пошуку і выпраўлення памылак.\n\nУ некаторых журналах можа ўтрымлівацца канфідэнцыяльная інфармацыя, таму давайце доступ да ўсіх журналаў прылады толькі тым праграмам, якім вы давяраеце. \n\nКалі вы не дасце гэтай праграме доступу да ўсіх журналаў прылад, у яе ўсё роўна застанецца доступ да ўласных журналаў. Для вытворцы вашай прылады будуць даступнымі некаторыя журналы і інфармацыя на вашай прыладзе."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Журналы прылад запісваюць усё, што адбываецца на вашай прыладзе. Праграмы выкарыстоўваюць гэтыя журналы для пошуку і выпраўлення памылак.\n\nУ некаторых журналах можа ўтрымлівацца канфідэнцыяльная інфармацыя, таму давайце доступ да ўсіх журналаў прылады толькі тым праграмам, якім вы давяраеце. \n\nКалі вы не дасце гэтай праграме доступу да ўсіх журналаў прылад, у яе ўсё роўна застанецца доступ да ўласных журналаў. Для вытворцы вашай прылады будуць даступнымі некаторыя журналы і інфармацыя на вашай прыладзе.\n\nДаведайцеся больш на старонцы g.co/android/devicelogs."</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-bg/strings.xml b/core/res/res/values-bg/strings.xml
index a56f24c..f9d61bc 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"В регистрационните файлове за устройството се записва какво се извършва на него. Приложенията могат да използват тези регистрационни файлове, за да откриват и отстраняват проблеми.\n\nНякои регистрационни файлове за устройството може да съдържат поверителна информация, затова разрешавайте достъп до всички тях само на приложения, на които имате доверие. \n\nАко не разрешите на това приложение достъп до всички регистрационни файлове за устройството, то пак може да осъществява достъп до собствените си регистрационни файлове. Производителят на устройството пак може да има достъп до някои регистрационни файлове или информация на устройството ви."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"В регистрационните файлове за устройството се записва какво се извършва на него. Приложенията могат да използват тези регистрационни файлове, за да откриват и отстраняват проблеми.\n\nНякои регистрационни файлове за устройството може да съдържат поверителна информация, затова разрешавайте достъп до всички тях само на приложения, на които имате доверие. \n\nАко не разрешите на това приложение достъп до всички регистрационни файлове за устройството, то пак може да осъществява достъп до собствените си регистрационни файлове. Производителят на устройството пак може да има достъп до някои регистрационни файлове или информация на устройството ви."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"В регистрационните файлове за устройството се записва какво се извършва на него. Приложенията могат да използват тези регистрационни файлове, за да откриват и отстраняват проблеми.\n\nНякои регистрационни файлове за устройството може да съдържат поверителна информация, затова разрешавайте достъп до всички тях само на приложения, на които имате доверие. \n\nАко не разрешите на това приложение достъп до всички регистрационни файлове за устройството, то пак може да осъществява достъп до собствените си регистрационни файлове. Производителят на устройството може да има достъп до някои регистрационни файлове или информация на устройството ви.\n\nНаучете повече на адрес g.co/android/devicelogs."</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 30c1b95..6da6267 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই সব ডিভাইসের লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারকও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই সব ডিভাইসের লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারকও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ, সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই ডিভাইসের সব লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারক এখনও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।\n\ng.co/android/devicelogs লিঙ্ক থেকে আরও জানুন।"</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 cceba58..e597330 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Zapisnici uređaja bilježe šta se dešava na uređaju. Aplikacije mogu koristiti te zapisnike da pronađu i riješe probleme.\n\nNeki zapisnici mogu sadržavati osjetljive podatke. Zbog toga pristup svim zapisnicima uređaja dozvolite samo aplikacijama koje smatrate pouzdanima. \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 moći pristupiti nekim zapisnicima ili podacima na uređaju.\n\nSaznajte više na g.co/android/devicelogs."</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 3b4c571..b52e57a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1948,10 +1948,10 @@
     <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store no està disponible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"La configuració d\'Android TV no està disponible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"La configuració de la tauleta no està disponible"</string>
-    <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"La configuració del telèfon no està disponible"</string>
+    <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Configuració del telèfon no disponible"</string>
     <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al dispositiu Android TV."</string>
     <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho a la tauleta."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"En aquests moments, no es pot accedir a aquesta aplicació al dispositiu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al telèfon."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"No es pot accedir a aquesta aplicació al teu <xliff:g id="DEVICE">%1$s</xliff:g>. Prova-ho al telèfon."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Aquesta aplicació sol·licita seguretat addicional. Prova-ho al dispositiu Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Aquesta aplicació sol·licita seguretat addicional. Prova-ho a la tauleta."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Aquesta aplicació sol·licita seguretat addicional. Prova-ho al telèfon."</string>
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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ó accedeixi 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.\n\nObtén més informació a g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 721f596..e7af3c0 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -2052,7 +2052,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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í.\n\nDalší informace najdete na stránce g.co/android/devicelogs."</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 53297dc..b04d8c9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1949,9 +1949,9 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-indstillingerne er ikke tilgængelige"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tabletindstillingerne er ikke tilgængelige"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefonindstillingerne er ikke tilgængelige"</string>
-    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
-    <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
+    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
+    <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Denne app anmoder om yderligere sikkerhed. Prøv på din Android TV-enhed i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Denne app anmoder om yderligere sikkerhed. Prøv på din tablet i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Denne app anmoder om yderligere sikkerhed. Prøv på din telefon i stedet."</string>
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nFå flere oplysninger på g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 0bdfd8f..43ee44f 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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 Zugang zu einigen Protokollen oder Informationen auf deinem Gerät.\n\nWeitere Informationen findest du unter g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a3e2826..9ee2e49 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή σε πληροφορίες στη συσκευή σας.\n\nΜάθετε περισσότερα στη διεύθυνση g.co/android/devicelogs."</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>
@@ -2289,7 +2290,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> εκτελείται στο παρασκήνιο. Πατήστε για διαχείριση της χρήσης της μπαταρίας."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> μπορεί να επηρεάσει τη διάρκεια ζωής μπαταρίας. Πατήστε για έλεγχο των ενεργών εφαρμογών."</string>
     <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="default" msgid="6102378580971542473">"Δεν είναι δυνατή η πρόσβαση στην κάμερα τηλεφώνου από το <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Δεν είναι δυνατή η πρόσβαση στην κάμερα του tablet από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Δεν είναι δυνατή η πρόσβαση σε αυτό το στοιχείο κατά τη ροή. Δοκιμάστε στο τηλέφωνό σας."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Προεπιλογή συστήματος"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 88433c6..bde1fe0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLearn more at g.co/android/devicelogs."</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 24d135d..cbed459 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLearn more at g.co/android/devicelogs."</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 3e758be..fcd40c5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLearn more at g.co/android/devicelogs."</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 9f251ca..e583cef 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLearn more at g.co/android/devicelogs."</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 60675ba..77a1af6 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‎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.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎Learn more at g.co/android/devicelogs.‎‏‎‎‏‎"</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 1d6cd7d..2a3f916 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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 los registros las apps que sean de tu confianza. \n\nTen en cuenta que la app puede acceder a sus propios registros incluso si no permites que acceda a todos los registros del dispositivo. También es posible que el fabricante del dispositivo acceda a algunos registros o información en tu dispositivo.\n\nObtén más información en g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1195e54..90f1006 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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, podrá seguir accediendo a sus propios registros. El fabricante de tu dispositivo aún puede acceder a algunos registros o información de tu dispositivo.\n\nObtén más información en g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 3f7586e..f11e893 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLugege lisateavet aadressil g.co/android/devicelogs."</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>
@@ -2289,7 +2290,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"Rakendus <xliff:g id="APP">%1$s</xliff:g> töötab taustal. Puudutage akukasutuse haldamiseks."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> võib aku tööiga mõjutada. Puudutage aktiivsete rakenduste ülevaatamiseks."</string>
     <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="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>
     <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>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 29f0cab..15b25ad 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -56,7 +56,7 @@
     </plurals>
     <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="ClipMmi" msgid="4110549342447630629">"Deitzailearen identitatea (jasotako deiak)"</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>
@@ -71,12 +71,12 @@
     <string name="RuacMmi" msgid="1876047385848991110">"Nahigabeko dei gogaikarriak ukatzea"</string>
     <string name="CndMmi" msgid="185136449405618437">"Deitzailearen zenbakia ematea"</string>
     <string name="DndMmi" msgid="8797375819689129800">"Ez molestatzeko modua"</string>
-    <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenekin"</string>
-    <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"Deien identifikazio-zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenik gabe"</string>
-    <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenekin"</string>
-    <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Deien identifikazio-zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenik gabe"</string>
+    <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"Deitzailearen identitatea zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenekin"</string>
+    <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"Deitzailearen identitatea adierazteko zerbitzuaren balio lehenetsiak murriztapenak ezartzen ditu. Hurrengo deia: murriztapenik gabe."</string>
+    <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"Deitzailearen identitatea zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenekin."</string>
+    <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"Deitzailearen identitatea zerbitzuaren balio lehenetsiak ez du murriztapenik ezartzen. Hurrengo deia: murriztapenik gabe."</string>
     <string name="serviceNotProvisioned" msgid="8289333510236766193">"Zerbitzua ez da hornitu."</string>
-    <string name="CLIRPermanent" msgid="166443681876381118">"Ezin duzu deien identifikazio-zerbitzuaren ezarpena aldatu."</string>
+    <string name="CLIRPermanent" msgid="166443681876381118">"Ezin duzu aldatu deitzailearen identitatearen ezarpena."</string>
     <string name="RestrictedOnDataTitle" msgid="1500576417268169774">"Ez dago mugikorreko datu-zerbitzurik"</string>
     <string name="RestrictedOnEmergencyTitle" msgid="2852916906106191866">"Ezin da egin larrialdi-deirik"</string>
     <string name="RestrictedOnNormalTitle" msgid="7009474589746551737">"Ez dago ahots-deien zerbitzurik"</string>
@@ -524,9 +524,9 @@
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez tableta soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Multidifusio-helbideak erabiliz wifi-sare bateko gailu guztiei (ez bakarrik Android TV gailuari) bidalitako paketeak jasotzeko baimena ematen die aplikazioei. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Wi-Fi sarearen bidez gailu guztiei bidalitako paketeak jasotzeko baimena ematen die aplikazioei multidifusio-helbideak erabilita, ez telefonoa soilik. Multidifusiokoa ez den moduak baino bateria gehiago erabiltzen du."</string>
-    <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"atzitu Bluetooth-aren ezarpenak"</string>
+    <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"atzitu Bluetootharen ezarpenak"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Tokiko Bluetooth tableta konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei."</string>
-    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Android TV gailuan Bluetooth-a konfiguratzeko eta urruneko gailuak hautemateko eta haiekin parekatzeko baimena ematen die aplikazioei."</string>
+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Android TV gailuan Bluetootha konfiguratzeko eta urruneko gailuak hautemateko eta haiekin parekatzeko baimena ematen die aplikazioei."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Tokiko Bluetooth telefonoa konfiguratzea eta urruneko gailuak detektatzea eta haiekin parekatzea baimentzen die aplikazioei."</string>
     <string name="permlab_accessWimaxState" msgid="7029563339012437434">"WiMAX sarera konektatzea eta deskonektatzea"</string>
     <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"WiMAX gaituta dagoen zehazteko eta konektatutako WiMAX sareei buruzko informazioa ikusteko baimena ematen die aplikazioei."</string>
@@ -1310,7 +1310,7 @@
   <string-array name="network_switch_type_name">
     <item msgid="2255670471736226365">"datu-konexioa"</item>
     <item msgid="5520925862115353992">"Wifia"</item>
-    <item msgid="1055487873974272842">"Bluetooth-a"</item>
+    <item msgid="1055487873974272842">"Bluetootha"</item>
     <item msgid="1616528372438698248">"Ethernet"</item>
     <item msgid="9177085807664964627">"VPNa"</item>
   </string-array>
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLortu informazio gehiago g.co/android/devicelogs helbidean."</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>
@@ -2108,7 +2109,7 @@
     <string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> kalkulu-orria"</string>
     <string name="mime_type_presentation" msgid="1145384236788242075">"Aurkezpena"</string>
     <string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> aurkezpena"</string>
-    <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth-ak aktibatuta jarraituko du hegaldi moduan"</string>
+    <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetoothak aktibatuta jarraituko du hegaldi moduan"</string>
     <string name="car_loading_profile" msgid="8219978381196748070">"Kargatzen"</string>
     <string name="file_count" msgid="3220018595056126969">"{count,plural, =1{{file_name} eta beste # fitxategi}other{{file_name} eta beste # fitxategi}}"</string>
     <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Ez dago edukia partekatzeko pertsona gomendaturik"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fb28a13..e192475 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"گزارش‌های دستگاه آنچه را در دستگاهتان رخ می‌دهد ثبت می‌کند. برنامه‌ها می‌توانند از این گزارش‌ها برای پیدا کردن مشکلات و رفع آن‌ها استفاده کنند.\n\nبرخی‌از گزارش‌ها ممکن است حاوی اطلاعات حساس باشند، بنابراین فقط به برنامه‌های مورداعتمادتان اجازه دسترسی به همه گزارش‌های دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارش‌های دستگاه دسترسی داشته باشد، همچنان می‌تواند به گزارش‌های خودش دسترسی داشته باشد. سازنده دستگاه نیز ممکن است همچنان بتواند به برخی‌از گزارش‌ها یا اطلاعات دستگاهتان دسترسی داشته باشد."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"گزارش‌های دستگاه آنچه را در دستگاهتان رخ می‌دهد ثبت می‌کند. برنامه‌ها می‌توانند از این گزارش‌ها برای پیدا کردن مشکلات و رفع آن‌ها استفاده کنند.\n\nبرخی‌از گزارش‌ها ممکن است حاوی اطلاعات حساس باشند، بنابراین فقط به برنامه‌های مورداعتمادتان اجازه دسترسی به همه گزارش‌های دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارش‌های دستگاه دسترسی داشته باشد، همچنان می‌تواند به گزارش‌های خودش دسترسی داشته باشد. سازنده دستگاه نیز ممکن است همچنان بتواند به برخی‌از گزارش‌ها یا اطلاعات دستگاهتان دسترسی داشته باشد."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"‏گزارش‌های دستگاه آنچه را در دستگاهتان رخ می‌دهد ثبت می‌کند. برنامه‌ها می‌توانند از این گزارش‌ها برای پیدا کردن مشکلات و رفع آن‌ها استفاده کنند.\n\nبرخی‌از گزارش‌ها ممکن است حاوی اطلاعات حساس باشند، بنابراین فقط به برنامه‌های مورداعتمادتان اجازه دسترسی به همه گزارش‌های دستگاه را بدهید. \n\nاگر به این برنامه اجازه ندهید به همه گزارش‌های دستگاه دسترسی داشته باشد، همچنان می‌تواند به گزارش‌های خودش دسترسی داشته باشد. سازنده دستگاه نیز ممکن است همچنان بتواند به برخی‌از گزارش‌ها یا اطلاعات دستگاهتان دسترسی داشته باشد.\n\nاطلاعات بیشتر: g.co/android/devicelogs."</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>
@@ -2289,7 +2290,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> در پس‌زمینه درحال اجرا است. برای مدیریت مصرف باتری ضربه بزنید."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> ممکن است بر عمر باتری تأثیر بگذارد. برای مرور برنامه‌های فعال، ضربه بزنید."</string>
     <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="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>
     <string name="vdm_secure_window" msgid="161700398158812314">"درحین جاری‌سازی، نمی‌توانید به آن دسترسی داشته باشید. دسترسی به آن را در تلفنتان امتحان کنید."</string>
     <string name="system_locale_title" msgid="711882686834677268">"پیش‌فرض سیستم"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3bf9128..5c1335c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nLue lisää osoitteessa g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 67a5d4f..104808b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1950,15 +1950,15 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Paramètres Android TV non accessibles"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Paramètres de la tablette non accessibles"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Paramètres du téléphone non accessibles"</string>
-    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre appareil Android TV à la place."</string>
-    <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre tablette à la place."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre téléphone à la place."</string>
+    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre appareil Android TV à la place."</string>
+    <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre tablette à la place."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g> pour le moment. Essayez sur votre téléphone à la place."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Cette application demande une sécurité supplémentaire. Essayez sur votre appareil Android TV à la place."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Cette application demande une sécurité supplémentaire. Essayez sur votre tablette à la place."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Cette application demande une sécurité supplémentaire. Essayez sur votre téléphone à la place."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre appareil Android TV à la place."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre tablette à la place."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Impossible d\'accéder à ce contenu sur votre appareil <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre téléphone à la place."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre appareil Android TV à la place."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre tablette à la place."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Impossible d\'accéder à ce contenu sur votre <xliff:g id="DEVICE">%1$s</xliff:g>. Essayez sur votre téléphone à la place."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Cette application a été conçue pour une ancienne version d\'Android et pourrait ne pas fonctionner correctement. Essayez de vérifier les mises à jour ou communiquez avec son développeur."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Vérifier la présence de mises à jour"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Vous avez de nouveaux messages"</string>
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nPour en savoir plus, consultez la page g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index a844870..7f099b0 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Les journaux enregistrent ce qui se passe sur votre appareil. Les applis peuvent les utiliser pour rechercher et résoudre des 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.\n\nEn savoir plus sur g.co/android/devicelogs"</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>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 0d2ea3c..9b68186 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -213,7 +213,7 @@
     <string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcións da tableta"</string>
     <string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcións de Android TV"</string>
     <string name="power_dialog" product="default" msgid="1107775420270203046">"Opcións do teléfono"</string>
-    <string name="silent_mode" msgid="8796112363642579333">"Modo de silencio"</string>
+    <string name="silent_mode" msgid="8796112363642579333">"Modo silencioso"</string>
     <string name="turn_on_radio" msgid="2961717788170634233">"Activar a conexión sen fíos"</string>
     <string name="turn_off_radio" msgid="7222573978109933360">"Desactivar a conexión sen fíos"</string>
     <string name="screen_lock" msgid="2072642720826409809">"Bloqueo de pantalla"</string>
@@ -257,7 +257,7 @@
     <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Vaise facer unha captura de pantalla para o informe de erro dentro de # segundo.}other{Vaise facer unha captura de pantalla para o informe de erro dentro de # segundos.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Realizouse a captura de pantalla co informe de erros"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Produciuse un erro ao realizar a captura de pantalla co informe de erros"</string>
-    <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo de silencio"</string>
+    <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modo silencioso"</string>
     <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"O son está desactivado"</string>
     <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"O son está activado"</string>
     <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Modo avión"</string>
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nConsulta máis información en g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 494158c..fa3784fa 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે.\n\ng.co/android/devicelogs પર વધુ જાણો."</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-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 41436f0..79faaac 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1948,7 +1948,7 @@
     <string name="app_streaming_blocked_title_for_playstore_dialog" msgid="8149823099822897538">"Play Store उपलब्ध नहीं है"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV की सेटिंग उपलब्ध नहीं हैं"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"टैबलेट की सेटिंग उपलब्ध नहीं हैं"</string>
-    <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"फ़ोन की सेटिंग उपलब्ध नहीं हैं"</string>
+    <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"फ़ोन की सेटिंग उपलब्ध नहीं है"</string>
     <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने Android TV डिवाइस पर कोशिश करें."</string>
     <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने टैबलेट पर कोशिश करें."</string>
     <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"इस समय, आपके <xliff:g id="DEVICE">%1$s</xliff:g> पर इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर कोशिश करें."</string>
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"डिवाइस लॉग में, आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें ठीक करने के लिए करते हैं.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह डिवाइस पर अपने लॉग को ऐक्सेस कर सकता है. डिवाइस को बनाने वाली कंपनी अब भी डिवाइस के कुछ लॉग या जानकारी को ऐक्सेस कर सकती है."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"डिवाइस लॉग में, आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें ठीक करने के लिए करते हैं.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस लॉग का ऐक्सेस दें. \n\nअगर इस ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी यह डिवाइस पर अपने लॉग को ऐक्सेस कर सकता है. डिवाइस को बनाने वाली कंपनी अब भी डिवाइस के कुछ लॉग या जानकारी को ऐक्सेस कर सकती है."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"डिवाइस लॉग में आपके डिवाइस पर की गई कार्रवाइयां रिकॉर्ड होती हैं. ऐप्लिकेशन, इन लॉग का इस्तेमाल गड़बड़ियां ढूंढने और उन्हें सही करने के लिए करता है.\n\nकुछ लॉग में संवेदनशील जानकारी हो सकती है. इसलिए, सिर्फ़ भरोसेमंद ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस दें. \n\nअगर किसी ऐप्लिकेशन को डिवाइस के सभी लॉग का ऐक्सेस नहीं दिया जाता है, तब भी वह डिवाइस पर अपने लॉग को ऐक्सेस कर सकता है. डिवाइस को बनाने वाली कंपनी अब भी डिवाइस के कुछ लॉग या जानकारी को ऐक्सेस कर सकती है.\n\nज़्यादा जानने के लिए, g.co/android/devicelogs पर जाएं."</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 38ca0f8..fb95a1f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nSaznajte više na g.co/android/devicelogs."</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 764a721..6c700dd1 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nTovábbi információ: g.co/android/devicelogs."</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 a72e9d1..2e78dfd 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Այն, ինչ տեղի է ունենում ձեր սարքում, գրանցվում է սարքի մատյաններում։ Հավելվածները կարող են դրանք օգտագործել անսարքությունները հայտնաբերելու և վերացնելու նպատակով։\n\nՔանի որ որոշ մատյաններ անձնական տեղեկություններ են պարունակում, խորհուրդ ենք տալիս հասանելի դարձնել ձեր սարքի բոլոր մատյանները միայն այն հավելվածներին, որոնց վստահում եք։ \n\nԵթե այս հավելվածին նման թույլտվություն չեք տվել, դրան նախկինի պես հասանելի կլինեն իր մատյանները։ Հնարավոր է՝ ձեր սարքի արտադրողին ևս հասանելի լինեն սարքի որոշ մատյաններ և տեղեկություններ։"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Այն, ինչ տեղի է ունենում ձեր սարքում, գրանցվում է սարքի մատյաններում։ Հավելվածները կարող են դրանք օգտագործել անսարքությունները հայտնաբերելու և վերացնելու նպատակով։\n\nՔանի որ որոշ մատյաններ անձնական տեղեկություններ են պարունակում, խորհուրդ ենք տալիս հասանելի դարձնել ձեր սարքի բոլոր մատյանները միայն այն հավելվածներին, որոնց վստահում եք։ \n\nԵթե այս հավելվածին նման թույլտվություն չեք տվել, դրան նախկինի պես հասանելի կլինեն իր մատյանները։ Հնարավոր է՝ ձեր սարքի արտադրողին ևս հասանելի լինեն սարքի որոշ մատյաններ և տեղեկություններ։"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Այն, ինչ տեղի է ունենում ձեր սարքում, գրանցվում է սարքի մատյաններում։ Հավելվածները կարող են դրանք օգտագործել անսարքությունները հայտնաբերելու և վերացնելու նպատակով։\n\nՔանի որ որոշ մատյաններ անձնական տեղեկություններ են պարունակում, խորհուրդ ենք տալիս հասանելի դարձնել ձեր սարքի բոլոր մատյանները միայն այն հավելվածներին, որոնց վստահում եք։ \n\nԵթե այս հավելվածին նման թույլտվություն չեք տվել, դրան նախկինի պես հասանելի կլինեն իր մատյանները։ Հնարավոր է՝ ձեր սարքի արտադրողին ևս հասանելի լինեն սարքի որոշ մատյաններ և տեղեկություններ։\n\nՄանրամասների համար այցելեք g.co/android/devicelogs էջ։"</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-in/strings.xml b/core/res/res/values-in/strings.xml
index c75b2e0..41b3959 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nPelajari lebih lanjut di g.co/android/devicelogs."</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 ed4f28f..9396d89 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nNánar á g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 5728bd3..c0d2526 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1942,7 +1942,7 @@
     <string name="app_blocked_title" msgid="7353262160455028160">"L\'app non è disponibile"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> non è al momento disponibile."</string>
     <string name="app_streaming_blocked_title" msgid="6090945835898766139">"<xliff:g id="ACTIVITY">%1$s</xliff:g> non disponibile"</string>
-    <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"È necessaria l\'autorizzazione"</string>
+    <string name="app_streaming_blocked_title_for_permission_dialog" msgid="4483161748582966785">"Autorizzazione necessaria"</string>
     <string name="app_streaming_blocked_title_for_camera_dialog" msgid="3935701653713853065">"Fotocamera non disponibile"</string>
     <string name="app_streaming_blocked_title_for_fingerprint_dialog" msgid="3516853717714141951">"Continua sul telefono"</string>
     <string name="app_streaming_blocked_title_for_microphone_dialog" msgid="544822455127171206">"Microfono non disponibile"</string>
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nScopri di più all\'indirizzo g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 7bba4a9..59408a7 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1953,13 +1953,13 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"ההגדרות של הטלפון לא זמינות"</string>
     <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‏אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות במכשיר Android TV."</string>
     <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטאבלט."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטלפון."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, אפשר לנסות בטלפון."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"‏האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות במכשיר Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות בטאבלט."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות בטלפון."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"‏אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, יש לנסות במכשיר Android TV."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, יש לנסות בטאבלט."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, יש לנסות בטלפון."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, אפשר לנסות בטלפון."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"‏האפליקציה הזו עוצבה לגרסה ישנה יותר של Android וייתכן שלא תפעל כראוי. ניתן לבדוק אם יש עדכונים או ליצור קשר עם המפתח."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"יש עדכון חדש?"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"יש לך הודעות חדשות"</string>
@@ -2052,7 +2052,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ביומני המכשיר מתועדת הפעילות במכשיר. האפליקציות יכולות להשתמש ביומנים האלה כדי למצוא בעיות ולפתור אותן.\n\nהמידע בחלק מהיומנים יכול להיות רגיש, לכן יש לתת הרשאת גישה לכל יומני המכשיר רק לאפליקציות מהימנות. \n\nגם אם האפליקציה הזו לא תקבל הרשאת גישה לכל יומני המכשיר, היא תוכל לגשת ליומנים שלה. יכול להיות שליצרן המכשיר עדיין תהיה גישה לחלק מהיומנים או למידע במכשיר שלך."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ביומני המכשיר מתועדת הפעילות במכשיר. האפליקציות יכולות להשתמש ביומנים האלה כדי למצוא בעיות ולפתור אותן.\n\nהמידע בחלק מהיומנים יכול להיות רגיש, לכן יש לתת הרשאת גישה לכל יומני המכשיר רק לאפליקציות מהימנות. \n\nגם אם האפליקציה הזו לא תקבל הרשאת גישה לכל יומני המכשיר, היא תוכל לגשת ליומנים שלה. יכול להיות שליצרן המכשיר עדיין תהיה גישה לחלק מהיומנים או למידע במכשיר שלך."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"‏ביומני המכשיר מתועדת הפעילות במכשיר. האפליקציות יכולות להשתמש ביומנים האלה כדי למצוא בעיות ולפתור אותן.\n\nהמידע בחלק מהיומנים יכול להיות רגיש, לכן יש לתת הרשאת גישה לכל היומנים של המכשיר רק לאפליקציות שסומכים עליהן. \n\nגם אם האפליקציה הזו לא תקבל הרשאת גישה לכל יומני המכשיר, היא תוכל לגשת ליומנים שלה. יכול להיות שליצרן המכשיר עדיין תהיה גישה לחלק מהיומנים או למידע במכשיר שלך.\n\nמידע נוסף זמין בכתובת g.co/android/devicelogs."</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,6 +2294,6 @@
     <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>
-    <string name="vdm_secure_window" msgid="161700398158812314">"אי אפשר לגשת לתוכן המאובטח הזה בזמן סטרימינג. במקום זאת, יש לנסות בטלפון."</string>
+    <string name="vdm_secure_window" msgid="161700398158812314">"אי אפשר לגשת לתוכן המאובטח הזה בזמן סטרימינג. במקום זאת, אפשר לנסות בטלפון."</string>
     <string name="system_locale_title" msgid="711882686834677268">"ברירת המחדל של המערכת"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 26c26b2..c48d37c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合も、このアプリはアプリ独自のログにアクセスできます。また、デバイスのメーカーもデバイスの一部のログや情報にアクセスできる可能性があります。"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合も、このアプリはアプリ独自のログにアクセスできます。また、デバイスのメーカーもデバイスの一部のログや情報にアクセスできる可能性があります。"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合でも、このアプリはアプリ独自のログにアクセスできます。また、デバイスの製造メーカーもデバイスの一部のログや情報にアクセスできる可能性があります。\n\n詳しくは、g.co/android/devicelogs をご覧ください。"</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 2818c46..9cc6ae4 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა თქვენს ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა თქვენს ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა საკუთარ ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა.\n\n შეიტყვეთ მეტი g.co/android/devicelogs."</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 cdbfa37..5db972e 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Журналдарға құрылғыда не болып жатқаны жазылады. Қолданбалар осы журналдарды қате тауып, түзету үшін пайдаланады.\n\nКейбір журналдарда құпия ақпарат болуы мүмкін. Сондықтан барлық құрылғының журналын пайдалану рұқсаты тек сенімді қолданбаларға берілуі керек. \n\nБұл қолданбаға барлық құрылғының журналын пайдалануға рұқсат бермесеңіз де, ол өзінің журналдарын пайдалана береді. Құрылғы өндірушісі де құрылғыдағы кейбір журналдарды немесе ақпаратты пайдалануы мүмкін."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Журналдарға құрылғыда не болып жатқаны жазылады. Қолданбалар осы журналдарды қате тауып, түзету үшін пайдаланады.\n\nКейбір журналдарда құпия ақпарат болуы мүмкін. Сондықтан барлық құрылғының журналын пайдалану рұқсаты тек сенімді қолданбаларға берілуі керек. \n\nБұл қолданбаға барлық құрылғының журналын пайдалануға рұқсат бермесеңіз де, ол өзінің журналдарын пайдалана береді. Құрылғы өндірушісі де құрылғыдағы кейбір журналдарды немесе ақпаратты пайдалануы мүмкін."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Журналдарға құрылғыда не болып жатқаны жазылады. Қолданбалар осы журналдарды қате тауып, түзету үшін пайдаланады.\n\nКейбір журналдарда құпия ақпарат болуы мүмкін. Сондықтан барлық құрылғының журналын пайдалану рұқсаты тек сенімді қолданбаларға берілуі керек. \n\nБұл қолданбаға барлық құрылғының журналын пайдалануға рұқсат бермесеңіз де, ол өзінің журналдарын пайдалана береді. Құрылғы өндірушісі де құрылғыдағы кейбір журналдарды немесе ақпаратты пайдалануы мүмкін.\n\nТолық ақпарат: g.co/android/devicelogs."</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-km/strings.xml b/core/res/res/values-km/strings.xml
index 7ffd8b4..73f7d86 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"កំណត់ហេតុឧបករណ៍កត់ត្រាអ្វីដែលកើតឡើងនៅលើឧបករណ៍របស់អ្នក។ កម្មវិធីអាចប្រើកំណត់ហេតុទាំងនេះដើម្បីស្វែងរក និងដោះស្រាយបញ្ហាបាន។\n\nកំណត់ហេតុមួយចំនួនអាចមានព័ត៌មានរសើប ដូច្នេះគួរអនុញ្ញាតឱ្យចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់សម្រាប់តែកម្មវិធីដែលអ្នកទុកចិត្តប៉ុណ្ណោះ។ \n\nប្រសិនបើអ្នកមិនអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ទេ វានៅតែអាចចូលប្រើកំណត់ហេតុរបស់វាផ្ទាល់បាន។ ក្រុមហ៊ុន​ផលិត​ឧបករណ៍របស់អ្នក​ប្រហែលជា​នៅតែអាចចូលប្រើ​កំណត់ហេតុ ឬព័ត៌មានមួយចំនួន​នៅលើឧបករណ៍​របស់អ្នក​បានដដែល។"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"កំណត់ហេតុឧបករណ៍កត់ត្រាអ្វីដែលកើតឡើងនៅលើឧបករណ៍របស់អ្នក។ កម្មវិធីអាចប្រើកំណត់ហេតុទាំងនេះដើម្បីស្វែងរក និងដោះស្រាយបញ្ហាបាន។\n\nកំណត់ហេតុមួយចំនួនអាចមានព័ត៌មានរសើប ដូច្នេះគួរអនុញ្ញាតឱ្យចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់សម្រាប់តែកម្មវិធីដែលអ្នកទុកចិត្តប៉ុណ្ណោះ។ \n\nប្រសិនបើអ្នកមិនអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ទេ វានៅតែអាចចូលប្រើកំណត់ហេតុរបស់វាផ្ទាល់បាន។ ក្រុមហ៊ុន​ផលិត​ឧបករណ៍របស់អ្នក​ប្រហែលជា​នៅតែអាចចូលប្រើ​កំណត់ហេតុ ឬព័ត៌មានមួយចំនួន​នៅលើឧបករណ៍​របស់អ្នក​បានដដែល។"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"កំណត់ហេតុឧបករណ៍កត់ត្រាអ្វីដែលកើតឡើងនៅលើឧបករណ៍របស់អ្នក។ កម្មវិធីអាចប្រើកំណត់ហេតុទាំងនេះដើម្បីស្វែងរក និងដោះស្រាយបញ្ហាបាន។\n\nកំណត់ហេតុមួយចំនួនអាចមានព័ត៌មានរសើប ដូច្នេះគួរអនុញ្ញាតឱ្យចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់សម្រាប់តែកម្មវិធីដែលអ្នកទុកចិត្តប៉ុណ្ណោះ។ \n\nប្រសិនបើអ្នកមិនអនុញ្ញាតឱ្យកម្មវិធីនេះចូលប្រើកំណត់ហេតុឧបករណ៍ទាំងអស់ទេ វានៅតែអាចចូលប្រើកំណត់ហេតុរបស់វាផ្ទាល់បាន។ ក្រុមហ៊ុន​ផលិត​ឧបករណ៍របស់អ្នក​ប្រហែលជា​នៅតែអាចចូលប្រើ​កំណត់ហេតុ ឬព័ត៌មានមួយចំនួន​នៅលើឧបករណ៍​របស់អ្នក​បានដដែល។\n\nស្វែងយល់បន្ថែមតាមរយៈ g.co/android/devicelogs។"</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-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 510c3d4..0c7d4b1 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್‌ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು ಈ ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಈಗಲೂ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್‌ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು ಈ ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಈಗಲೂ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್‌ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ನೀವು ಈ ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು. ಹಾಗಿದ್ದರೂ, ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಬಹುದು.\n\ng.co/android/devicelogs ನಲ್ಲಿ ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ."</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 fc975a3..9ab64e6 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1165,8 +1165,8 @@
     <string name="no" msgid="5122037903299899715">"취소"</string>
     <string name="dialog_alert_title" msgid="651856561974090712">"주의"</string>
     <string name="loading" msgid="3138021523725055037">"로드 중.."</string>
-    <string name="capital_on" msgid="2770685323900821829">"ON"</string>
-    <string name="capital_off" msgid="7443704171014626777">"OFF"</string>
+    <string name="capital_on" msgid="2770685323900821829">"사용 설정"</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>
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"기기 로그에 기기에서 발생한 상황이 기록됩니다. 앱은 문제를 찾고 해결하는 데 이 로그를 사용할 수 있습니다.\n\n일부 로그는 민감한 정보를 포함할 수 있으므로 신뢰할 수 있는 앱만 모든 기기 로그에 액세스하도록 허용하세요. \n\n앱에 전체 기기 로그에 대한 액세스 권한을 부여하지 않아도 앱이 자체 로그에는 액세스할 수 있습니다. 기기 제조업체에서 일부 로그 또는 기기 내 정보에 액세스할 수도 있습니다."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"기기 로그에 기기에서 발생한 상황이 기록됩니다. 앱은 문제를 찾고 해결하는 데 이 로그를 사용할 수 있습니다.\n\n일부 로그는 민감한 정보를 포함할 수 있으므로 신뢰할 수 있는 앱만 모든 기기 로그에 액세스하도록 허용하세요. \n\n앱에 전체 기기 로그에 대한 액세스 권한을 부여하지 않아도 앱이 자체 로그에는 액세스할 수 있습니다. 기기 제조업체에서 일부 로그 또는 기기 내 정보에 액세스할 수도 있습니다."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"기기 로그에는 기기에서 발생한 상황이 기록됩니다. 앱은 문제를 찾고 해결하는 데 이 로그를 사용할 수 있습니다.\n\n일부 로그에 민감한 정보가 포함될 수 있으므로 신뢰할 수 있는 앱만 모든 기기 로그에 액세스하도록 허용하세요. \n\n앱에 전체 기기 로그에 대한 액세스 권한을 부여하지 않아도, 앱이 자체 로그에는 액세스할 수 있습니다. 기기 제조업체에서 기기 내 일부 로그 또는 정보에 액세스할 수도 있습니다.\n\ng.co/android/devicelogs에서 자세히 알아보세요."</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-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 0cde52d..29e4616 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Түзмөктө аткарылган бардык аракеттер түзмөктүн таржымалдарында сакталып калат. Колдонмолор бул таржымалдарды колдонуп, маселелерди оңдошот.\n\nАйрым таржымалдарда купуя маалымат болушу мүмкүн, андыктан түзмөктөгү бардык таржымалдарды ишенимдүү колдонмолорго гана пайдаланууга уруксат бериңиз. \n\nЭгер бул колдонмого түзмөктөгү айрым таржымалдарга кирүүгө тыюу салсаңыз, ал өзүнүн таржымалдарын пайдалана берет. Түзмөктү өндүрүүчү түзмөгүңүздөгү айрым таржымалдарды же маалыматты көрө берет."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Түзмөктө аткарылган бардык аракеттер түзмөктүн таржымалдарында сакталып калат. Колдонмолор бул таржымалдарды колдонуп, маселелерди оңдошот.\n\nАйрым таржымалдарда купуя маалымат болушу мүмкүн, андыктан түзмөктөгү бардык таржымалдарды ишенимдүү колдонмолорго гана пайдаланууга уруксат бериңиз. \n\nЭгер бул колдонмого түзмөктөгү айрым таржымалдарга кирүүгө тыюу салсаңыз, ал өзүнүн таржымалдарын пайдалана берет. Түзмөктү өндүрүүчү түзмөгүңүздөгү айрым таржымалдарды же маалыматты көрө берет."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Түзмөктө жасалган нерселердин баары таржымалга сактала берет. Колдонмолор анын жардамы менен көйгөйлөрдү аныктап, оңдоп турушат.\n\nАйрым таржымалдарда купуя маалымат болушу мүмкүн, андыктан ишенимдүү колдонмолорго гана түзмөктөгү бардык таржымалдарды пайдаланууга уруксат бериңиз. \n\nЭгер бул колдонмого түзмөктөгү айрым таржымалдарга кирүүгө тыюу салсаңыз, ал өзүнүн таржымалдарын пайдалана берет. Түзмөктү өндүрүүчү түзмөгүңүздөгү айрым таржымалдарды же маалыматты көрө берет.\n\nКеңири маалымат: g.co/android/devicelogs."</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 b2677e2..81ec5b7 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້.\n\nສຶກສາເພີ່ມເຕີມໄດ້ຢູ່ g.co/android/devicelogs."</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-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 99f44b2..ab0ba3c 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -2052,7 +2052,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Įrenginyje įrašoma, kas jame įvyksta. Programos gali naudoti šiuos žurnalus, kai reikia surasti ir išspręsti 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.\n\nSužinokite daugiau adresu g.co/android/devicelogs."</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 62ab61e..688d6b2 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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ē.\n\nŠeit varat uzzināt vairāk: g.co/android/devicelogs"</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>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 7d3cb81..667f502 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот.\n\nДознајте повеќе на g.co/android/devicelogs."</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-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 74ab9f1..4bd2001 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്‌സസ് ചെയ്യാനായേക്കും."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്‌സസ് ചെയ്യാനായേക്കും."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്‌സസ് ചെയ്യാനായേക്കും.\n\ng.co/android/devicelogs എന്നതിൽ കൂടുതലറിയുക."</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 9c0e6d3..1b92252 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Tаны төхөөрөмж үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Tаны төхөөрөмж үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Таны төхөөрөмжийн үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй.\n\ng.co/android/devicelogs -с нэмэлт мэдээлэл аваарай."</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 d2dbddf..fd7ce2e 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो.\n\ng.co/android/devicelogs येथे अधिक जाणून घ्या."</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 a0c9e5a..5a623be 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Log peranti merekodkan perkara yang berlaku pada peranti anda. Apl boleh menggunakan log ini untuk menemukan dan membetulkan masalah.\n\nSesetengah log mungkin mengandungi maklumat sensitif, jadi hanya benarkan apl yang anda percaya untuk mengakses semua log peranti. \n\nJika anda tidak membenarkan apl ini mengakses semua log peranti, apl ini masih boleh mengakses log sendiri. Pengilang peranti anda mungkin masih dapat mengakses sesetengah log atau maklumat pada peranti anda.\n\nKetahui lebih lanjut di g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index e4c4131..5027a7f 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"သင့်စက်ရှိ အဖြစ်အပျက်များကို စက်မှတ်တမ်းများက မှတ်တမ်းတင်သည်။ အက်ပ်များက ပြဿနာများ ရှာဖွေပြီးဖြေရှင်းရန် ဤမှတ်တမ်းများကို သုံးနိုင်သည်။\n\nအချို့မှတ်တမ်းများတွင် သတိထားရမည့်အချက်အလက်များ ပါဝင်နိုင်သဖြင့် စက်မှတ်တမ်းအားလုံးကို ယုံကြည်ရသည့် အက်ပ်များကိုသာ သုံးခွင့်ပြုပါ။ \n\nဤအက်ပ်ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်မပြုသော်လည်း ၎င်းက ၎င်း၏ကိုယ်ပိုင်မှတ်တမ်းကို သုံးနိုင်ဆဲဖြစ်သည်။ သင့်စက်ရှိ အချို့မှတ်တမ်းများ (သို့) အချက်အလက်များကို သင့်စက်ထုတ်လုပ်သူက သုံးနိုင်ပါသေးသည်။"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"သင့်စက်ရှိ အဖြစ်အပျက်များကို စက်မှတ်တမ်းများက မှတ်တမ်းတင်သည်။ အက်ပ်များက ပြဿနာများ ရှာဖွေပြီးဖြေရှင်းရန် ဤမှတ်တမ်းများကို သုံးနိုင်သည်။\n\nအချို့မှတ်တမ်းများတွင် သတိထားရမည့်အချက်အလက်များ ပါဝင်နိုင်သဖြင့် စက်မှတ်တမ်းအားလုံးကို ယုံကြည်ရသည့် အက်ပ်များကိုသာ သုံးခွင့်ပြုပါ။ \n\nဤအက်ပ်ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်မပြုသော်လည်း ၎င်းက ၎င်း၏ကိုယ်ပိုင်မှတ်တမ်းကို သုံးနိုင်ဆဲဖြစ်သည်။ သင့်စက်ရှိ အချို့မှတ်တမ်းများ (သို့) အချက်အလက်များကို သင့်စက်ထုတ်လုပ်သူက သုံးနိုင်ပါသေးသည်။"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"သင့်စက်ရှိ အဖြစ်အပျက်များကို စက်မှတ်တမ်းများက မှတ်တမ်းတင်သည်။ အက်ပ်များက ပြဿနာများ ရှာဖွေပြီးဖြေရှင်းရန် ဤမှတ်တမ်းများကို သုံးနိုင်သည်။\n\nအချို့မှတ်တမ်းများတွင် သတိထားရမည့်အချက်အလက်များ ပါဝင်နိုင်သဖြင့် ယုံကြည်ရသည့် အက်ပ်များကိုသာ စက်မှတ်တမ်းအားလုံး သုံးခွင့်ပြုပါ။ \n\nဤအက်ပ်ကို စက်မှတ်တမ်းအားလုံး သုံးခွင့်မပြုသော်လည်း ၎င်းက ကိုယ်ပိုင်မှတ်တမ်းများ သုံးနိုင်သေးသည်။ သင့်စက်ရှိ မှတ်တမ်း (သို့) အချက်အလက်အချို့ကို စက်ထုတ်လုပ်သူက သုံးနိုင်သေးသည်။\n\ng.co/android/devicelogs တွင် ပိုမိုလေ့လာပါ။"</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 762a03e..abc5867 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Enhetslogger registrerer det som skjer på enheten. 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.\n\nFinn ut mer på g.co/android/devicelogs."</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 1ad85c8..3397643 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"डिभाइसका लगले तपाईंको डिभाइसमा भएका विभिन्न गतिविधिको अभिलेख राख्छ। एपहरू यी लगका आधारमा समस्या पत्ता लगाउन र तिनको समाधान गर्न सक्छन्।\n\nकेही लगहरूमा संवेदनशील जानकारी समावेश हुन सक्ने भएकाले आफूले भरोसा गर्ने एपलाई मात्र डिभाइसका सबै लग हेर्ने अनुमति दिनुहोस्। \n\nतपाईंले यो एपलाई डिभाइसका सबै लग हेर्ने अनुमति दिनुभएन भने पनि यसले आफ्नै लग भने हेर्न सक्छ। तपाईंको डिभाइसको उत्पादकले पनि तपाईंको डिभाइसमा भएका केही लग वा जानकारी हेर्न सक्ने सम्भावना हुन्छ।"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"डिभाइसका लगले तपाईंको डिभाइसमा भएका विभिन्न गतिविधिको अभिलेख राख्छ। एपहरू यी लगका आधारमा समस्या पत्ता लगाउन र तिनको समाधान गर्न सक्छन्।\n\nकेही लगहरूमा संवेदनशील जानकारी समावेश हुन सक्ने भएकाले आफूले भरोसा गर्ने एपलाई मात्र डिभाइसका सबै लग हेर्ने अनुमति दिनुहोस्। \n\nतपाईंले यो एपलाई डिभाइसका सबै लग हेर्ने अनुमति दिनुभएन भने पनि यसले आफ्नै लग भने हेर्न सक्छ। तपाईंको डिभाइसको उत्पादकले पनि तपाईंको डिभाइसमा भएका केही लग वा जानकारी हेर्न सक्ने सम्भावना हुन्छ।"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"डिभाइसका लगले तपाईंको डिभाइसमा भएका विभिन्न गतिविधिको अभिलेख राख्छ। एपहरू यी लगका आधारमा समस्या पत्ता लगाउन र तिनको समाधान गर्न सक्छन्।\n\nकेही लगहरूमा संवेदनशील जानकारी समावेश हुन सक्ने भएकाले आफूले भरोसा गर्ने एपलाई मात्र डिभाइसका सबै लग हेर्ने अनुमति दिनुहोस्। \n\nतपाईंले यो एपलाई डिभाइसका सबै लग हेर्ने अनुमति दिनुभएन भने पनि यसले आफ्नै लग भने हेर्न सक्छ। तपाईंको डिभाइसको उत्पादकले पनि तपाईंको डिभाइसमा भएका केही लग वा जानकारी हेर्न सक्ने सम्भावना हुन्छ।\n\nतपाईं यस सम्बन्धमा थप जान्न चाहनुहुन्छ भने g.co/android/devicelogs मा जानुहोस्।"</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 9b30b8b..251a53a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nGa voor meer informatie naar g.co/android/devicelogs."</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 2829730..26bfeb4 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।\n\ng.co/android/devicelogsରେ ଅଧିକ ଜାଣନ୍ତୁ।"</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 85b9433..b61b0fe 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।\n\ng.co/android/devicelogs \'ਤੇ ਹੋਰ ਜਾਣੋ।"</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-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 73ccd5a..7193eb7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2052,7 +2052,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nWięcej informacji znajdziesz na stronie g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 1bcb2ec..c1c0d54 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nSaiba mais em g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fb61ef3..1fe6e1c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -186,7 +186,7 @@
     <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>
     <string name="work_profile_deleted" msgid="5891181538182009328">"Perfil de trabalho eliminado"</string>
-    <string name="work_profile_deleted_details" msgid="3773706828364418016">"A app de administração do perfil de trabalho está em falta ou danificada. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
+    <string name="work_profile_deleted_details" msgid="3773706828364418016">"A app de administração do perfil de trabalho está em falta ou danificada. Por isso, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O seu perfil de trabalho já não está disponível neste dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiadas tentativas de introdução da palavra-passe"</string>
     <string name="device_ownership_relinquished" msgid="4080886992183195724">"O administrador anulou o dispositivo para utilização pessoal."</string>
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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 só deve 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.\n\nSaiba mais em g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 1bcb2ec..c1c0d54 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nSaiba mais em g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index da105b9..129f8fe 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -44,16 +44,16 @@
     <string name="mmiComplete" msgid="6341884570892520140">"MMI finalizat."</string>
     <string name="badPin" msgid="888372071306274355">"Codul PIN vechi introdus nu este corect."</string>
     <string name="badPuk" msgid="4232069163733147376">"Codul PUK introdus nu este corect."</string>
-    <string name="mismatchPin" msgid="2929611853228707473">"Codurile PIN introduse nu se potrivesc."</string>
+    <string name="mismatchPin" msgid="2929611853228707473">"PIN-urile introduse nu sunt identice."</string>
     <string name="invalidPin" msgid="7542498253319440408">"Introdu un cod PIN alcătuit din 4 până la 8 cifre."</string>
     <string name="invalidPuk" msgid="8831151490931907083">"Introdu un cod PUK care să aibă 8 cifre sau mai mult."</string>
     <string name="needPuk" msgid="7321876090152422918">"Cardul SIM este blocat cu codul PUK. Introdu codul PUK pentru a-l debloca."</string>
     <string name="needPuk2" msgid="7032612093451537186">"Introdu codul PUK2 pentru a debloca cardul SIM."</string>
     <string name="enablePin" msgid="2543771964137091212">"Operațiunea nu a reușit. Activează blocarea cardului SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
-      <item quantity="few">V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări până la blocarea cardului SIM.</item>
-      <item quantity="other">V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări până la blocarea cardului SIM.</item>
-      <item quantity="one">V-a mai rămas <xliff:g id="NUMBER_0">%d</xliff:g> încercare până la blocarea cardului SIM.</item>
+      <item quantity="few">Ți-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări până la blocarea cardului SIM.</item>
+      <item quantity="other">Ți-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> de încercări până la blocarea cardului SIM.</item>
+      <item quantity="one">Ți-a mai rămas <xliff:g id="NUMBER_0">%d</xliff:g> încercare până la blocarea cardului SIM.</item>
     </plurals>
     <string name="imei" msgid="2157082351232630390">"IMEI"</string>
     <string name="meid" msgid="3291227361605924674">"MEID"</string>
@@ -85,9 +85,9 @@
     <string name="RestrictedStateContent" msgid="7693575344608618926">"Dezactivat temporar de operator"</string>
     <string name="RestrictedStateContentMsimTemplate" msgid="5228235722511044687">"Dezactivat temporar de operator pentru numărul de card SIM <xliff:g id="SIMNUMBER">%d</xliff:g>"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="1008329951315753038">"Nu se poate stabili conexiunea la rețeaua mobilă"</string>
-    <string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Încercați să schimbați rețeaua preferată. Atingeți pentru a schimba."</string>
+    <string name="NetworkPreferenceSwitchSummary" msgid="2086506181486324860">"Încearcă să schimbi rețeaua preferată. Atinge pentru a schimba."</string>
     <string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"Apelurile de urgență nu sunt disponibile"</string>
-    <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nu puteți efectua apeluri de urgență prin Wi-Fi"</string>
+    <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"Nu poți face apeluri de urgență prin Wi-Fi"</string>
     <string name="notification_channel_network_alert" msgid="4788053066033851841">"Alerte"</string>
     <string name="notification_channel_call_forward" msgid="8230490317314272406">"Redirecționarea apelurilor"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Mod de apelare inversă de urgență"</string>
@@ -128,7 +128,7 @@
     <item msgid="468830943567116703">"Pentru a face apeluri și a trimite mesaje prin Wi-Fi, mai întâi solicită configurarea acestui serviciu la operator. Apoi, activează din nou apelarea prin Wi-Fi din Setări. (Cod de eroare: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="4795145070505729156">"A apărut o problemă la înregistrarea apelării prin Wi‑Fi la operatorul dvs.: <xliff:g id="CODE">%1$s</xliff:g>"</item>
+    <item msgid="4795145070505729156">"A apărut o problemă la înregistrarea apelării prin Wi‑Fi la operatorul tău: <xliff:g id="CODE">%1$s</xliff:g>"</item>
   </string-array>
     <!-- no translation found for wfcSpnFormat_spn (2982505428519096311) -->
     <skip />
@@ -145,7 +145,7 @@
     <string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
     <string name="wifi_calling_off_summary" msgid="5626710010766902560">"Dezactivată"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1035175836270943089">"Apelează prin Wi-Fi"</string>
-    <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Apelați prin rețeaua mobilă"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="4958965609212575619">"Sună prin rețeaua mobilă"</string>
     <string name="wfc_mode_wifi_only_summary" msgid="104951993894678665">"Numai Wi-Fi"</string>
     <!-- no translation found for crossSimFormat_spn (9125246077491634262) -->
     <skip />
@@ -176,7 +176,7 @@
     <string name="notification_title" msgid="5783748077084481121">"Eroare de conectare pentru <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
     <string name="contentServiceSync" msgid="2341041749565687871">"Sincronizare"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"Nu se poate sincroniza"</string>
-    <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"Ați încercat să ștergeți prea multe <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
+    <string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"Ai încercat să ștergi prea multe <xliff:g id="CONTENT_TYPE">%s</xliff:g>."</string>
     <string name="low_memory" product="tablet" msgid="5557552311566179924">"Stocarea pe tabletă este plină. Șterge câteva fișiere pentru a elibera spațiu."</string>
     <string name="low_memory" product="watch" msgid="3479447988234030194">"Spațiul de stocare de pe ceas este plin! Șterge câteva fișiere pentru a elibera spațiu."</string>
     <string name="low_memory" product="tv" msgid="6663680413790323318">"Spațiul de stocare de pe dispozitivul Android TV este plin. Șterge câteva fișiere pentru a elibera spațiu."</string>
@@ -186,13 +186,13 @@
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"De administratorul profilului de serviciu"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"De <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="work_profile_deleted" msgid="5891181538182009328">"Profilul de serviciu a fost șters"</string>
-    <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplicația de administrare a profilului de serviciu lipsește sau este deteriorată. Prin urmare, profilul de serviciu și datele asociate au fost șterse. Pentru asistență, contactați administratorul."</string>
+    <string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplicația de administrare a profilului de serviciu lipsește sau este deteriorată. Prin urmare, profilul de serviciu și datele asociate au fost șterse. Pentru asistență, contactează administratorul."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profilul de serviciu nu mai este disponibil pe acest dispozitiv"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Prea multe încercări de introducere a parolei"</string>
     <string name="device_ownership_relinquished" msgid="4080886992183195724">"Administratorul a retras dispozitivul pentru uz personal"</string>
     <string name="network_logging_notification_title" msgid="554983187553845004">"Dispozitivul este gestionat"</string>
-    <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizația dvs. gestionează acest dispozitiv și poate monitoriza traficul în rețea. Atingeți pentru mai multe detalii."</string>
-    <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplicațiile vă pot accesa locația"</string>
+    <string name="network_logging_notification_text" msgid="1327373071132562512">"Organizația ta gestionează acest dispozitiv și poate monitoriza traficul în rețea. Atinge pentru mai multe detalii."</string>
+    <string name="location_changed_notification_title" msgid="3620158742816699316">"Aplicațiile îți pot accesa locația"</string>
     <string name="location_changed_notification_text" msgid="7158423339982706912">"Contactează administratorul IT pentru a afla mai multe"</string>
     <string name="geofencing_service" msgid="3826902410740315456">"Serviciul de delimitare geografică"</string>
     <string name="country_detector" msgid="7023275114706088854">"Detector de țară"</string>
@@ -204,10 +204,10 @@
     <string name="device_policy_manager_service" msgid="5085762851388850332">"Serviciul Manager de politici pentru dispozitive"</string>
     <string name="music_recognition_manager_service" msgid="7481956037950276359">"Serviciu de gestionare a recunoașterii de melodii"</string>
     <string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string>
-    <string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string>
+    <string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi folosită. Dispozitivul va fi șters.\n\nDacă ai întrebări, contactează administratorul organizației."</string>
     <string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
     <string name="personal_apps_suspension_title" msgid="7561416677884286600">"Activează profilul de serviciu"</string>
-    <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplicațiile personale sunt blocate până când activați profilul de serviciu"</string>
+    <string name="personal_apps_suspension_text" msgid="6115455688932935597">"Aplicațiile personale sunt blocate până când activezi profilul de serviciu"</string>
     <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"Aplicațiile personale vor fi blocate pe <xliff:g id="DATE">%1$s</xliff:g>, la <xliff:g id="TIME">%2$s</xliff:g>. Administratorul IT nu permite ca profilul de serviciu să fie dezactivat mai mult de <xliff:g id="NUMBER">%3$d</xliff:g> zile."</string>
     <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"Activează"</string>
     <string name="me" msgid="6207584824693813140">"Eu"</string>
@@ -229,11 +229,11 @@
     <string name="reboot_to_reset_title" msgid="2226229680017882787">"Revenire la setările din fabrică"</string>
     <string name="reboot_to_reset_message" msgid="3347690497972074356">"Se repornește…"</string>
     <string name="shutdown_progress" msgid="5017145516412657345">"Se închide..."</string>
-    <string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Computerul dvs. tablet PC se va închide."</string>
+    <string name="shutdown_confirm" product="tablet" msgid="2872769463279602432">"Tableta se va închide."</string>
     <string name="shutdown_confirm" product="tv" msgid="7975942887313518330">"Dispozitivul Android TV se va închide."</string>
-    <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Ceasul dvs. se va închide."</string>
-    <string name="shutdown_confirm" product="default" msgid="136816458966692315">"Telefonul dvs. se va închide."</string>
-    <string name="shutdown_confirm_question" msgid="796151167261608447">"Doriți să închideți?"</string>
+    <string name="shutdown_confirm" product="watch" msgid="2977299851200240146">"Ceasul se va închide."</string>
+    <string name="shutdown_confirm" product="default" msgid="136816458966692315">"Telefonul se va închide."</string>
+    <string name="shutdown_confirm_question" msgid="796151167261608447">"Vrei să închizi?"</string>
     <string name="reboot_safemode_title" msgid="5853949122655346734">"Repornește în modul sigur"</string>
     <string name="reboot_safemode_confirm" msgid="1658357874737219624">"Repornești în modul sigur? Astfel vor fi dezactivate toate aplicațiile terță parte instalate. Acestea vor fi restabilite când repornești dispozitivul."</string>
     <string name="recent_tasks_title" msgid="8183172372995396653">"Recente"</string>
@@ -250,7 +250,7 @@
     <string name="global_action_logout" msgid="6093581310002476511">"Încheie sesiunea"</string>
     <string name="global_action_screenshot" msgid="2610053466156478564">"Instantaneu"</string>
     <string name="bugreport_title" msgid="8549990811777373050">"Raport de eroare"</string>
-    <string name="bugreport_message" msgid="5212529146119624326">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
+    <string name="bugreport_message" msgid="5212529146119624326">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Ai răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
     <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"Raport interactiv"</string>
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"Folosește această opțiune în majoritatea situațiilor. Astfel, poți să urmărești progresul raportului, să introduci mai multe detalii în privința problemei și să creezi capturi de ecran. Pot fi omise unele secțiuni mai puțin folosite pentru care raportarea durează prea mult."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Raport complet"</string>
@@ -296,16 +296,16 @@
     <string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="8974401416068943888">"Mod sigur"</string>
     <string name="android_system_label" msgid="5974767339591067210">"Sistemul Android"</string>
-    <string name="user_owner_label" msgid="8628726904184471211">"Comutați la profilul personal"</string>
-    <string name="managed_profile_label" msgid="7316778766973512382">"Comutați la profilul de serviciu"</string>
+    <string name="user_owner_label" msgid="8628726904184471211">"Comută la profilul personal"</string>
+    <string name="managed_profile_label" msgid="7316778766973512382">"Comută la profilul de serviciu"</string>
     <string name="permgrouplab_contacts" msgid="4254143639307316920">"Agendă"</string>
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"să acceseze agenda"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"Locație"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"să acceseze locația acestui dispozitiv"</string>
     <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
-    <string name="permgroupdesc_calendar" msgid="6762751063361489379">"acceseze calendarul"</string>
+    <string name="permgroupdesc_calendar" msgid="6762751063361489379">"să acceseze calendarul"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="5726462398070064542">"trimită și să vadă mesajele SMS"</string>
+    <string name="permgroupdesc_sms" msgid="5726462398070064542">"să trimită și să vadă mesajele SMS"</string>
     <string name="permgrouplab_storage" msgid="17339216290379241">"Fișiere"</string>
     <string name="permgroupdesc_storage" msgid="5378659041354582769">"să acceseze fișiere de pe dispozitiv"</string>
     <string name="permgrouplab_readMediaAural" msgid="1858331312624942053">"Muzică și conținut audio"</string>
@@ -319,7 +319,7 @@
     <string name="permgrouplab_camera" msgid="9090413408963547706">"Camera foto"</string>
     <string name="permgroupdesc_camera" msgid="7585150538459320326">"fotografieze și să înregistreze videoclipuri"</string>
     <string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Dispozitive din apropiere"</string>
-    <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"descoperiți dispozitive din apropiere și conectați-vă la acestea"</string>
+    <string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"descoperă dispozitive din apropiere și conectează-te la acestea"</string>
     <string name="permgrouplab_calllog" msgid="7926834372073550288">"Jurnale de apeluri"</string>
     <string name="permgroupdesc_calllog" msgid="2026996642917801803">"să citească și să scrie jurnalul de apeluri telefonice"</string>
     <string name="permgrouplab_phone" msgid="570318944091926620">"Telefon"</string>
@@ -328,19 +328,19 @@
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"să acceseze datele de la senzori despre semnele vitale"</string>
     <string name="permgrouplab_notifications" msgid="5472972361980668884">"Notificări"</string>
     <string name="permgroupdesc_notifications" msgid="4608679556801506580">"să afișeze notificări"</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Analizeze conținutul ferestrei"</string>
-    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspectează conținutul unei ferestre cu care interacționați."</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"să preia conținutul ferestrei"</string>
+    <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Inspectează conținutul unei ferestre cu care interacționezi."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"să activeze funcția Explorează prin atingere"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"Elementele atinse vor fi rostite cu voce tare, iar ecranul poate fi explorat utilizând gesturi."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"Remarce textul pe care îl introduceți"</string>
-    <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Include date personale, cum ar fi numere ale cardurilor de credit sau parole."</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2772371671541753254">"să vadă textul pe care îl introduci"</string>
+    <string name="capability_desc_canRequestFilterKeyEvents" msgid="2381315802405773092">"Include date cu caracter personal, cum ar fi numere ale cardurilor de credit sau parole."</string>
     <string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Controlează mărirea pe afișaj"</string>
     <string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Controlează nivelul de zoom și poziționarea afișajului."</string>
     <string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Folosește gesturi"</string>
     <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Poate atinge, glisa, ciupi sau folosi alte gesturi."</string>
-    <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Redea gesturi ce implică amprente"</string>
+    <string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"să redea gesturi ce implică amprente"</string>
     <string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Poate reda gesturile făcute pe senzorul de amprentă al dispozitivului."</string>
-    <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Faceți o captură de ecran"</string>
+    <string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Fă o captură de ecran"</string>
     <string name="capability_desc_canTakeScreenshot" msgid="7762297374317934052">"Poate face o captură de ecran."</string>
     <string name="permlab_statusBar" msgid="8798267849526214017">"dezactivare sau modificare bare de stare"</string>
     <string name="permdesc_statusBar" msgid="5809162768651019642">"Permite aplicației să dezactiveze bara de stare sau să adauge și să elimine pictograme de sistem."</string>
@@ -359,11 +359,11 @@
     <string name="permlab_answerPhoneCalls" msgid="4131324833663725855">"să răspundă la apeluri telefonice"</string>
     <string name="permdesc_answerPhoneCalls" msgid="894386681983116838">"Permite aplicației să răspundă la un apel telefonic."</string>
     <string name="permlab_receiveSms" msgid="505961632050451881">"primește mesaje text (SMS)"</string>
-    <string name="permdesc_receiveSms" msgid="1797345626687832285">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
+    <string name="permdesc_receiveSms" msgid="1797345626687832285">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitiv fără a ți le arăta."</string>
     <string name="permlab_receiveMms" msgid="4000650116674380275">"primește mesaje text (MMS)"</string>
     <string name="permdesc_receiveMms" msgid="958102423732219710">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitiv fără a ți le arăta."</string>
     <string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"Redirecționează mesajele cu transmisie celulară"</string>
-    <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite aplicației să se conecteze la modulul de transmisie celulară pentru a redirecționa mesajele cu transmisie celulară pe măsură ce le primește. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgență."</string>
+    <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Permite aplicației să se conecteze la modulul de transmisie celulară pentru a redirecționa mesajele cu transmisie celulară pe măsură ce le primește. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a te avertiza cu privire la situațiile de urgență. Aplicațiile rău intenționate pot afecta performanța sau funcționarea dispozitivului când e primită o transmisie celulară de urgență."</string>
     <string name="permlab_manageOngoingCalls" msgid="281244770664231782">"Să gestioneze apelurile în desfășurare"</string>
     <string name="permdesc_manageOngoingCalls" msgid="7003138133829915265">"Permite unei aplicații să vadă detalii despre apelurile în desfășurare de pe dispozitiv și să gestioneze apelurile respective."</string>
     <string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"citește mesajele cu transmisie celulară"</string>
@@ -377,7 +377,7 @@
     <string name="permdesc_readSms" product="tv" msgid="3054753345758011986">"Această aplicație poate să citească toate mesajele SMS (texT) stocate pe dispozitivul Android TV."</string>
     <string name="permdesc_readSms" product="default" msgid="774753371111699782">"Această aplicație poate citi toate mesajele SMS stocate pe telefon."</string>
     <string name="permlab_receiveWapPush" msgid="4223747702856929056">"primește mesaje text (WAP)"</string>
-    <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau șterge mesajele care v-au fost trimise fără a vi le arăta."</string>
+    <string name="permdesc_receiveWapPush" msgid="1638677888301778457">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau șterge mesajele care ți-au fost trimise fără a ți le arăta."</string>
     <string name="permlab_getTasks" msgid="7460048811831750262">"preluare aplicații care rulează"</string>
     <string name="permdesc_getTasks" msgid="7388138607018233726">"Permite aplicației să preia informațiile despre activitățile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"să gestioneze profilul și proprietarii dispozitivului"</string>
@@ -403,7 +403,7 @@
     <string name="permlab_getPackageSize" msgid="375391550792886641">"măsurare spațiu de stocare al aplicației"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modifică setări de sistem"</string>
-    <string name="permdesc_writeSettings" msgid="8293047411196067188">"Permite aplicației să modifice datele din setările sistemului. Aplicațiile rău intenționate pot corupe configurația sistemului dvs."</string>
+    <string name="permdesc_writeSettings" msgid="8293047411196067188">"Permite aplicației să modifice datele din setările sistemului. Aplicațiile rău intenționate pot corupe configurația sistemului."</string>
     <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"rulează la pornire"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea tabletei poate dura mai mult timp, iar rularea continuă a aplicației poate încetini dispozitivul."</string>
     <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"Permite aplicației să pornească imediat ce s-a terminat încărcarea sistemului. Din acest motiv, pornirea dispozitivului Android TV poate dura mai mult timp, iar rularea continuă a aplicației poate încetini dispozitivul."</string>
@@ -413,9 +413,9 @@
     <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze dispozitivul Android TV, determinându-l să utilizeze prea multă memorie."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
     <string name="permlab_readContacts" msgid="8776395111787429099">"citește agenda"</string>
-    <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă. Aplicațiile vor avea și acces la conturile de pe tabletă care au creat agenda. Aici pot fi incluse conturile create de aplicațiile pe care le-ați instalat. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
-    <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Permite aplicației să citească datele despre persoanele de contact din agenda stocată pe dispozitivul Android TV. Aplicațiile vor avea și acces la conturile de pe dispozitivul Android TV care au creat agenda. Aici pot fi incluse conturile create de aplicațiile pe care le-ați instalat. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
-    <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Permite aplicației să citească datele despre persoanele de contact salvate pe telefon. Aplicațiile vor avea și acces la conturile de pe telefon care au creat agenda. Aici pot fi incluse conturile create de aplicațiile pe care le-ați instalat. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă. Aplicațiile vor avea și acces la conturile de pe tabletă care au creat agenda. Aici pot fi incluse conturile create de aplicațiile pe care le-ai instalat. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău intenționate pot permite accesul la datele de contact fără cunoștința ta."</string>
+    <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"Permite aplicației să citească datele despre persoanele de contact din agenda stocată pe dispozitivul Android TV. Aplicațiile vor avea și acces la conturile de pe dispozitivul Android TV care au creat agenda. Aici pot fi incluse conturile create de aplicațiile pe care le-ai instalat. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău intenționate pot permite accesul la datele de contact fără cunoștința ta."</string>
+    <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"Permite aplicației să citească datele despre persoanele de contact salvate pe telefon. Aplicațiile vor avea și acces la conturile de pe telefon care au creat agenda. Aici pot fi incluse conturile create de aplicațiile pe care le-ai instalat. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău intenționate pot permite accesul la datele de contact fără cunoștința ta."</string>
     <string name="permlab_writeContacts" msgid="8919430536404830430">"modifică agenda"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă. Cu această permisiune, aplicația poate șterge datele de contact."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe dispozitivul Android TV. Cu această permisiune, aplicația poate șterge datele de contact."</string>
@@ -425,7 +425,7 @@
     <string name="permlab_writeCallLog" msgid="670292975137658895">"scrie jurnalul de apeluri"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="2657525794731690397">"Permite aplicației să modifice jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite sau făcute. Aplicațiile rău intenționate pot folosi această permisiune pentru a șterge sau a modifica jurnalul de apeluri."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="3934939195095317432">"Permite aplicației să modifice jurnalul de apeluri al dispozitivului Android TV, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="5903033505665134802">"Permite aplicației să modifice jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite sau făcute. Aplicațiile rău intenționate pot folosi această permisiune pentru a șterge sau a modifica jurnalul de apeluri."</string>
     <string name="permlab_bodySensors" msgid="662918578601619569">"Să acceseze date de la senzorii corporali, cum ar fi pulsul, în timpul folosirii"</string>
     <string name="permdesc_bodySensors" product="default" msgid="7652650410295512140">"Permite aplicației să acceseze date de la senzorii corporali, cum ar fi pulsul, temperatura și procentul de oxigen din sânge, în timpul folosirii aplicației."</string>
     <string name="permlab_bodySensors_background" msgid="4912560779957760446">"Să acceseze date de la senzorii corporali, precum pulsul, când rulează în fundal"</string>
@@ -441,10 +441,10 @@
     <string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"accesare comenzi suplimentare ale furnizorului locației"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
     <string name="permlab_accessFineLocation" msgid="6426318438195622966">"să acceseze locația exactă în prim-plan"</string>
-    <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Aplicația vă poate determina locația exactă cu ajutorul serviciilor de localizare atunci când este folosită. Pentru ca aplicația să poată determina locația, trebuie să activați serviciile de localizare pentru dispozitiv. Aceasta poate mări utilizarea bateriei."</string>
+    <string name="permdesc_accessFineLocation" msgid="6732174080240016335">"Aplicația îți poate stabili locația exactă cu ajutorul serviciilor de localizare când este folosită. Pentru ca aplicația să poată stabili locația, trebuie să activezi serviciile de localizare pentru dispozitiv. Aceasta poate mări utilizarea bateriei."</string>
     <string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"să acceseze locația aproximativă numai în prim-plan."</string>
-    <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Aplicația vă poate determina locația aproximativă cu ajutorul serviciilor de localizare atunci când este folosită. Pentru ca aplicația să poată determina locația, trebuie să activați serviciile de localizare pentru dispozitiv."</string>
-    <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"accesați locația în fundal"</string>
+    <string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"Aplicația îți poate stabili locația aproximativă cu ajutorul serviciilor de localizare când este folosită. Pentru ca aplicația să poată stabili locația, trebuie să activezi serviciile de localizare pentru dispozitiv."</string>
+    <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"să acceseze locația în fundal"</string>
     <string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"Aplicația poate accesa locația oricând, chiar dacă nu este folosită."</string>
     <string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modificare setări audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
@@ -455,7 +455,7 @@
     <string name="permlab_sim_communication" msgid="176788115994050692">"să trimită comenzi către SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite aplicației să trimită comenzi pe cardul SIM. Această permisiune este foarte periculoasă."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"recunoașterea activității fizice"</string>
-    <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Această aplicație vă poate recunoaște activitatea fizică."</string>
+    <string name="permdesc_activityRecognition" msgid="8667484762991357519">"Această aplicație îți poate recunoaște activitatea fizică."</string>
     <string name="permlab_camera" msgid="6320282492904119413">"realizarea de fotografii și videoclipuri"</string>
     <string name="permdesc_camera" msgid="5240801376168647151">"Această aplicație poate să fotografieze și să înregistreze videoclipuri folosind camera foto când este în uz."</string>
     <string name="permlab_backgroundCamera" msgid="7549917926079731681">"să fotografieze și să înregistreze videoclipuri în fundal"</string>
@@ -468,9 +468,9 @@
     <string name="permdesc_vibrate" msgid="8733343234582083721">"Permite aplicației să controleze mecanismul de vibrare."</string>
     <string name="permdesc_vibrator_state" msgid="7050024956594170724">"Permite aplicației să acceseze modul de vibrații."</string>
     <string name="permlab_callPhone" msgid="1798582257194643320">"să sune direct la numere de telefon"</string>
-    <string name="permdesc_callPhone" msgid="5439809516131609109">"Permite aplicației să apeleze numere de telefon fără intervenția dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgență. Aplicațiile rău intenționate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
+    <string name="permdesc_callPhone" msgid="5439809516131609109">"Permite aplicației să apeleze numere de telefon fără intervenția ta. Acest lucru poate determina apariția unor taxe sau a unor apeluri neașteptate. Cu această permisiune aplicația nu poate apela numerele de urgență. Aplicațiile rău intenționate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
     <string name="permlab_accessImsCallService" msgid="442192920714863782">"accesează serviciul de apelare IMS"</string>
-    <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string>
+    <string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția ta."</string>
     <string name="permlab_readPhoneState" msgid="8138526903259297969">"citește starea și identitatea telefonului"</string>
     <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Permite aplicației să acceseze funcțiile de telefon ale dispozitivului. Cu această permisiune aplicația stabilește numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanță conectat printr-un apel."</string>
     <string name="permlab_readBasicPhoneState" msgid="3214853233263871347">"să citească informații de bază, precum activitatea și starea telefonului"</string>
@@ -507,8 +507,8 @@
     <string name="permdesc_setTimeZone" product="default" msgid="4611828585759488256">"Permite aplicației să schimbe fusul orar al telefonului."</string>
     <string name="permlab_getAccounts" msgid="5304317160463582791">"găsește conturi pe dispozitiv"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="1784452755887604512">"Permite aplicației să obțină lista de conturi cunoscute de tabletă. Aceasta poate include conturile create de aplicațiile pe care le-ai instalat."</string>
-    <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Permite aplicației să obțină lista conturilor cunoscute de dispozitivul Android TV. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Permite aplicației să obțină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ați instalat."</string>
+    <string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Permite aplicației să obțină lista conturilor cunoscute de dispozitivul Android TV. Aceasta poate include conturile create de aplicațiile pe care le-ai instalat."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Permite aplicației să obțină lista de conturi cunoscute de telefon. Aceasta poate include conturile create de aplicațiile pe care le-ai instalat."</string>
     <string name="permlab_accessNetworkState" msgid="2349126720783633918">"să vadă conexiunile la rețea"</string>
     <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Permite aplicației să vadă informațiile despre conexiunile la rețea, cum ar fi rețelele existente și cele care sunt conectate."</string>
     <string name="permlab_createNetworkSockets" msgid="3224420491603590541">"să aibă acces deplin la rețea"</string>
@@ -522,13 +522,13 @@
     <string name="permlab_changeWifiState" msgid="7947824109713181554">"se conectează și se deconectează de la Wi-Fi"</string>
     <string name="permdesc_changeWifiState" msgid="7170350070554505384">"Permite aplicației să se conecteze și să se deconecteze de la punctele de acces Wi-Fi, precum și să efectueze modificări în configurația dispozitivului pentru rețelele Wi-Fi."</string>
     <string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"permitere recepționare difuzare multiplă Wi-Fi"</string>
-    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar tableta dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="191079868596433554">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, folosind adrese cu difuzare multiplă, nu doar tableta ta. Această funcție folosește mai multă energie decât modul fără difuzare multiplă."</string>
     <string name="permdesc_changeWifiMulticastState" product="tv" msgid="1336952358450652595">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar dispozitivul Android TV. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
-    <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, utilizând adrese cu difuzare multiplă, nu doar telefonul dvs. Această funcție utilizează mai multă energie decât modul fără difuzare multiplă."</string>
+    <string name="permdesc_changeWifiMulticastState" product="default" msgid="8296627590220222740">"Permite aplicației să primească pachetele trimise către toate dispozitivele dintr-o rețea Wi-Fi, folosind adrese cu difuzare multiplă, nu doar telefonul tău. Această funcție folosește mai multă energie decât modul fără difuzare multiplă."</string>
     <string name="permlab_bluetoothAdmin" msgid="6490373569441946064">"accesează setările Bluetooth"</string>
-    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Permite aplicației să configureze tableta Bluetooth locală, să descopere și să se împerecheze cu dispozitive la distanță."</string>
-    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Permite aplicației să configureze conexiunea Bluetooth pe dispozitivul Android TV, să descopere și să se împerecheze cu dispozitive la distanță."</string>
-    <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Permite aplicației să configureze telefonul Bluetooth local, să descopere și să se împerecheze cu dispozitive la distanță."</string>
+    <string name="permdesc_bluetoothAdmin" product="tablet" msgid="5370837055438574863">"Permite aplicației să configureze tableta Bluetooth locală, să descopere și să se asocieze cu dispozitive la distanță."</string>
+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Permite aplicației să configureze conexiunea Bluetooth pe dispozitivul Android TV, să descopere și să se asocieze cu dispozitive la distanță."</string>
+    <string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Permite aplicației să configureze telefonul Bluetooth local, să descopere și să se asocieze cu dispozitive la distanță."</string>
     <string name="permlab_accessWimaxState" msgid="7029563339012437434">"se conectează și se deconectează de la WiMAX"</string>
     <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Permite aplicației să stabilească dacă o rețea WiMAX este activată și să vadă informațiile cu privire la toate rețelele WiMAX conectate."</string>
     <string name="permlab_changeWimaxState" msgid="6223305780806267462">"schimbă starea WiMAX"</string>
@@ -537,8 +537,8 @@
     <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Permite aplicației să conecteze și să deconecteze telefonul la și de la rețelele WiMAX."</string>
     <string name="permlab_bluetooth" msgid="586333280736937209">"conectează dispozitive Bluetooth"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Permite aplicației să vadă configurația tabletei Bluetooth, să facă și să accepte conexiuni cu dispozitive asociate."</string>
-    <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permite aplicației să vadă configurația conexiunii prin Bluetooth a dispozitivului Android TV, să efectueze și să accepte conexiuni cu dispozitive împerecheate."</string>
-    <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permite aplicației să vadă configurația telefonului Bluetooth, să efectueze și să accepte conexiuni cu dispozitive împerecheate."</string>
+    <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Permite aplicației să vadă configurația conexiunii prin Bluetooth a dispozitivului Android TV, să efectueze și să accepte conexiuni cu dispozitive asociate."</string>
+    <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Permite aplicației să vadă configurația telefonului Bluetooth, să stabilească și să accepte conexiuni cu dispozitive asociate."</string>
     <string name="permlab_bluetooth_scan" msgid="5402587142833124594">"să descopere și să asocieze dispozitive Bluetooth din apropiere"</string>
     <string name="permdesc_bluetooth_scan" product="default" msgid="6540723536925289276">"Permite aplicației să descopere și să asocieze dispozitive Bluetooth din apropiere"</string>
     <string name="permlab_bluetooth_connect" msgid="6657463246355003528">"să se conecteze la dispozitive Bluetooth asociate"</string>
@@ -555,47 +555,47 @@
     <string name="permdesc_nfc" msgid="8352737680695296741">"Permite aplicației să comunice cu etichetele, cardurile și cititoarele NFC (Near Field Communication)."</string>
     <string name="permlab_disableKeyguard" msgid="3605253559020928505">"dezactivează blocarea ecranului"</string>
     <string name="permdesc_disableKeyguard" msgid="3223710003098573038">"Permite aplicației să dezactiveze blocarea tastelor și orice modalitate asociată de securizare prin parolă. De exemplu, telefonul dezactivează blocarea tastelor când se primește un apel telefonic și reactivează blocarea tastelor la terminarea apelului."</string>
-    <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"solicitați complexitatea blocării ecranului"</string>
-    <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite aplicației să învețe nivelul de complexitate al blocării ecranului (ridicat, mediu, scăzut sau fără), fapt ce indică intervalul posibil de lungime a parolei și tipul de blocare a ecranului. Aplicația le poate sugera utilizatorilor să își actualizeze blocarea ecranului la un anumit nivel, dar utilizatorii pot ignora sugestia și pot naviga în continuare. Rețineți că blocarea ecranului nu este stocată ca text simplu, astfel încât aplicația să nu cunoască parola exactă."</string>
+    <string name="permlab_requestPasswordComplexity" msgid="1808977190557794109">"să solicite complexitatea blocării ecranului"</string>
+    <string name="permdesc_requestPasswordComplexity" msgid="1130556896836258567">"Permite aplicației să învețe nivelul de complexitate al blocării ecranului (ridicat, mediu, scăzut sau fără), fapt ce indică intervalul posibil de lungime a parolei și tipul de blocare a ecranului. Aplicația le poate sugera utilizatorilor să își actualizeze blocarea ecranului la un anumit nivel, dar utilizatorii pot ignora sugestia și pot naviga în continuare. Reține că blocarea ecranului nu e stocată ca text simplu, astfel încât aplicația să nu cunoască parola exactă."</string>
     <string name="permlab_postNotification" msgid="4875401198597803658">"să afișeze notificări"</string>
     <string name="permdesc_postNotification" msgid="5974977162462877075">"Permite aplicației să afișeze notificări"</string>
-    <string name="permlab_useBiometric" msgid="6314741124749633786">"utilizați hardware biometric"</string>
+    <string name="permlab_useBiometric" msgid="6314741124749633786">"să folosească hardware biometric"</string>
     <string name="permdesc_useBiometric" msgid="7502858732677143410">"Permite aplicației să folosească hardware biometric pentru autentificare"</string>
     <string name="permlab_manageFingerprint" msgid="7432667156322821178">"gestionează hardware-ul pentru amprentă"</string>
     <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Permite aplicației să invoce metode pentru a adăuga și pentru a șterge șabloane de amprentă pentru utilizare."</string>
     <string name="permlab_useFingerprint" msgid="1001421069766751922">"folosește hardware-ul pentru amprentă"</string>
     <string name="permdesc_useFingerprint" msgid="412463055059323742">"Permite aplicației să folosească hardware pentru amprentă pentru autentificare"</string>
-    <string name="permlab_audioWrite" msgid="8501705294265669405">"modificați colecția de muzică"</string>
+    <string name="permlab_audioWrite" msgid="8501705294265669405">"să modifice colecția de muzică"</string>
     <string name="permdesc_audioWrite" msgid="8057399517013412431">"Permite aplicației să modifice colecția de muzică."</string>
-    <string name="permlab_videoWrite" msgid="5940738769586451318">"modificați colecția de videoclipuri"</string>
-    <string name="permdesc_videoWrite" msgid="6124731210613317051">"Permite aplicației să vă modifice colecția de videoclipuri."</string>
-    <string name="permlab_imagesWrite" msgid="1774555086984985578">"modificați colecția de fotografii"</string>
-    <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite aplicației să vă modifice colecția de fotografii."</string>
-    <string name="permlab_mediaLocation" msgid="7368098373378598066">"citiți locațiile din colecția media"</string>
-    <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite aplicației să citească locațiile din colecția dvs. media."</string>
+    <string name="permlab_videoWrite" msgid="5940738769586451318">"să modifice colecția de videoclipuri"</string>
+    <string name="permdesc_videoWrite" msgid="6124731210613317051">"Permite aplicației să-ți modifice colecția de videoclipuri."</string>
+    <string name="permlab_imagesWrite" msgid="1774555086984985578">"să modifice colecția de fotografii"</string>
+    <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Permite aplicației să-ți modifice colecția de fotografii."</string>
+    <string name="permlab_mediaLocation" msgid="7368098373378598066">"să citească locațiile din colecția media"</string>
+    <string name="permdesc_mediaLocation" msgid="597912899423578138">"Permite aplicației să citească locațiile din colecția ta media."</string>
     <string name="biometric_app_setting_name" msgid="3339209978734534457">"Folosește sistemele biometrice"</string>
     <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Folosește sistemele biometrice sau blocarea ecranului"</string>
-    <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmați-vă identitatea"</string>
+    <string name="biometric_dialog_default_title" msgid="55026799173208210">"Confirmă-ți identitatea"</string>
     <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Folosește sistemele biometrice pentru a continua"</string>
     <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Folosește sistemele biometrice sau blocarea ecranului pentru a continua"</string>
     <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometric indisponibil"</string>
     <string name="biometric_error_user_canceled" msgid="6732303949695293730">"Autentificarea a fost anulată"</string>
     <string name="biometric_not_recognized" msgid="5106687642694635888">"Nu este recunoscut"</string>
     <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentificarea a fost anulată"</string>
-    <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nu este setat niciun cod PIN, model sau parolă"</string>
+    <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nu este setat un cod PIN, un model sau o parolă"</string>
     <string name="biometric_error_generic" msgid="6784371929985434439">"Eroare la autentificare"</string>
     <string name="screen_lock_app_setting_name" msgid="6054944352976789228">"Folosește blocarea ecranului"</string>
-    <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introduceți blocarea ecranului ca să continuați"</string>
+    <string name="screen_lock_dialog_default_subtitle" msgid="120359538048533695">"Introdu blocarea ecranului pentru a continua"</string>
     <string name="fingerprint_acquired_partial" msgid="4323789264604479684">"Apasă ferm pe senzor"</string>
     <string name="fingerprint_acquired_insufficient" msgid="623888149088216458">"Amprenta nu a fost recunoscută. Încearcă din nou."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Curățați senzorul de amprentă și încercați din nou"</string>
-    <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Curățați senzorul și încercați din nou"</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1770676120848224250">"Curăță senzorul de amprentă și încearcă din nou"</string>
+    <string name="fingerprint_acquired_imager_dirty_alt" msgid="9169582140486372897">"Curăță senzorul și încearcă din nou"</string>
     <string name="fingerprint_acquired_too_fast" msgid="1628459767349116104">"Apasă ferm pe senzor"</string>
     <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Ai mișcat degetul prea lent. Încearcă din nou."</string>
     <string name="fingerprint_acquired_already_enrolled" msgid="2285166003936206785">"Încearcă altă amprentă"</string>
     <string name="fingerprint_acquired_too_bright" msgid="3863560181670915607">"Prea luminos"</string>
     <string name="fingerprint_acquired_power_press" msgid="3107864151278434961">"S-a detectat apăsarea butonului de alimentare"</string>
-    <string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Încercați să ajustați"</string>
+    <string name="fingerprint_acquired_try_adjusting" msgid="3667006071003809364">"Încearcă să ajustezi"</string>
     <string name="fingerprint_acquired_immobile" msgid="1621891895241888048">"Schimbă ușor poziția degetului de fiecare dată"</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
@@ -615,7 +615,7 @@
     <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>
     <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Senzorul este dezactivat temporar."</string>
-    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Nu se poate folosi senzorul de amprentă. Vizitați un furnizor de servicii de reparații."</string>
+    <string name="fingerprint_error_bad_calibration" msgid="4385512597740168120">"Nu se poate folosi senzorul de amprentă. Vizitează un furnizor de servicii de reparații."</string>
     <string name="fingerprint_error_power_pressed" msgid="5479524500542129414">"A fost apăsat butonul de pornire"</string>
     <string name="fingerprint_name_template" msgid="8941662088160289778">"Degetul <xliff:g id="FINGERID">%d</xliff:g>"</string>
     <string name="fingerprint_app_setting_name" msgid="4253767877095495844">"Folosește amprenta"</string>
@@ -628,15 +628,15 @@
     <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string>
     <string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Deblocare facială"</string>
     <string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problemă cu Deblocarea facială"</string>
-    <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Atingeți pentru a șterge modelul facial, apoi adăugați din nou fața"</string>
+    <string name="face_recalibrate_notification_content" msgid="3064513770251355594">"Atinge pentru a șterge modelul facial, apoi adaugă din nou chipul"</string>
     <string name="face_setup_notification_title" msgid="8843461561970741790">"Configurează Deblocarea facială"</string>
-    <string name="face_setup_notification_content" msgid="5463999831057751676">"Deblocați-vă telefonul uitându-vă la acesta"</string>
-    <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Pentru a folosi Deblocarea facială, activați "<b>"Accesul la cameră"</b>" în Setări și confidențialitate"</string>
+    <string name="face_setup_notification_content" msgid="5463999831057751676">"Deblochează-ți telefonul uitându-te la el"</string>
+    <string name="face_sensor_privacy_enabled" msgid="7407126963510598508">"Pentru a folosi Deblocarea facială, activează "<b>"Accesul la cameră"</b>" în Setări și confidențialitate"</string>
     <string name="fingerprint_setup_notification_title" msgid="2002630611398849495">"Configurează mai multe moduri de deblocare"</string>
-    <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Atingeți ca să adăugați o amprentă"</string>
+    <string name="fingerprint_setup_notification_content" msgid="205578121848324852">"Atinge ca să adaugi o amprentă"</string>
     <string name="fingerprint_recalibrate_notification_name" msgid="1414578431898579354">"Deblocare cu amprenta"</string>
     <string name="fingerprint_recalibrate_notification_title" msgid="2406561052064558497">"Nu se poate folosi senzorul de amprentă"</string>
-    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizitați un furnizor de servicii de reparații."</string>
+    <string name="fingerprint_recalibrate_notification_content" msgid="8519935717822194943">"Vizitează un furnizor de servicii de reparații."</string>
     <string name="face_acquired_insufficient" msgid="6889245852748492218">"Nu se poate crea modelul facial. Reîncearcă."</string>
     <string name="face_acquired_too_bright" msgid="8070756048978079164">"Prea luminos. Încearcă o lumină mai slabă."</string>
     <string name="face_acquired_too_dark" msgid="8539853432479385326">"Lumină insuficientă"</string>
@@ -646,17 +646,17 @@
     <string name="face_acquired_too_low" msgid="4075391872960840081">"Mută telefonul mai jos"</string>
     <string name="face_acquired_too_right" msgid="6245286514593540859">"Mută telefonul spre stânga"</string>
     <string name="face_acquired_too_left" msgid="9201762240918405486">"Mută telefonul spre dreapta"</string>
-    <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Priviți mai direct spre dispozitiv."</string>
-    <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nu vi se vede fața. Țineți telefonul la nivelul ochilor."</string>
-    <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Prea multă mișcare. Țineți telefonul nemișcat."</string>
+    <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Privește mai direct spre dispozitiv."</string>
+    <string name="face_acquired_not_detected" msgid="1057966913397548150">"Nu ți se vede fața. Ține telefonul la nivelul ochilor."</string>
+    <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Prea multă mișcare. Ține telefonul nemișcat."</string>
     <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Reînregistrează-ți chipul."</string>
     <string name="face_acquired_too_different" msgid="2520389515612972889">"Chipul nu a fost recunoscut. Reîncearcă."</string>
     <string name="face_acquired_too_similar" msgid="8882920552674125694">"Schimbă ușor poziția capului"</string>
     <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"Priviți direct spre telefon"</string>
-    <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Priviți direct spre telefon"</string>
-    <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Priviți direct spre telefon"</string>
-    <string name="face_acquired_obscured" msgid="4917643294953326639">"Eliminați orice vă ascunde chipul."</string>
-    <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Curățați partea de sus a ecranului, inclusiv bara neagră"</string>
+    <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"Privește mai direct spre telefon"</string>
+    <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"Privește mai direct spre telefon"</string>
+    <string name="face_acquired_obscured" msgid="4917643294953326639">"Îndepărtează orice îți ascunde chipul."</string>
+    <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"Curăță partea de sus a ecranului, inclusiv bara neagră"</string>
     <!-- no translation found for face_acquired_dark_glasses_detected (5643703296620631986) -->
     <skip />
     <!-- no translation found for face_acquired_mouth_covering_detected (8219428572168642593) -->
@@ -675,14 +675,14 @@
     <string name="face_error_lockout_permanent" msgid="3277134834042995260">"Prea multe încercări. Deblocarea facială este dezactivată."</string>
     <string name="face_error_lockout_screen_lock" msgid="5062609811636860928">"Prea multe încercări. Folosește blocarea ecranului."</string>
     <string name="face_error_unable_to_process" msgid="5723292697366130070">"Nu se poate confirma fața. Încearcă din nou."</string>
-    <string name="face_error_not_enrolled" msgid="1134739108536328412">"Nu ați configurat Deblocarea facială"</string>
+    <string name="face_error_not_enrolled" msgid="1134739108536328412">"Nu ai configurat Deblocarea facială"</string>
     <string name="face_error_hw_not_present" msgid="7940978724978763011">"Deblocarea facială nu este acceptată pe acest dispozitiv"</string>
     <string name="face_error_security_update_required" msgid="5076017208528750161">"Senzorul este dezactivat temporar."</string>
     <string name="face_name_template" msgid="3877037340223318119">"Chip <xliff:g id="FACEID">%d</xliff:g>"</string>
     <string name="face_app_setting_name" msgid="5854024256907828015">"Folosește Deblocarea facială"</string>
     <string name="face_or_screen_lock_app_setting_name" msgid="1603149075605709106">"Folosește deblocarea facială sau ecranul de blocare"</string>
-    <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Folosiți-vă chipul ca să continuați"</string>
-    <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Folosiți-vă chipul sau blocarea ecranului pentru a continua"</string>
+    <string name="face_dialog_default_subtitle" msgid="6620492813371195429">"Folosește-ți chipul pentru a continua"</string>
+    <string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Folosește-ți chipul sau blocarea ecranului pentru a continua"</string>
   <string-array name="face_error_vendor">
   </string-array>
     <string name="face_error_vendor_unknown" msgid="7387005932083302070">"A apărut o eroare. Încearcă din nou."</string>
@@ -721,7 +721,7 @@
     <string name="permdesc_readNetworkUsageHistory" msgid="1112962304941637102">"Permite aplicației să citească utilizarea statistică a rețelei pentru anumite rețele și aplicații."</string>
     <string name="permlab_manageNetworkPolicy" msgid="6872549423152175378">"gestionează politica de rețea"</string>
     <string name="permdesc_manageNetworkPolicy" msgid="1865663268764673296">"Permite aplicației să gestioneze politicile de rețea și să definească regulile specifice aplicațiilor."</string>
-    <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"modificați modul de calcul al utilizării rețelei"</string>
+    <string name="permlab_modifyNetworkAccounting" msgid="7448790834938749041">"să modifice modul de calcul al utilizării rețelei"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5076042642247205390">"Permite aplicației să modifice modul în care este calculată utilizarea rețelei pentru aplicații. Nu se utilizează de aplicațiile obișnuite."</string>
     <string name="permlab_accessNotifications" msgid="7130360248191984741">"accesare notificări"</string>
     <string name="permdesc_accessNotifications" msgid="761730149268789668">"Permite aplicației să recupereze, să examineze și să șteargă notificări, inclusiv pe cele postate de alte aplicații."</string>
@@ -735,7 +735,7 @@
     <string name="permdesc_invokeCarrierSetup" msgid="4790845896063237887">"Permite proprietarului să apeleze aplicația de configurare furnizată de operator. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_accessNetworkConditions" msgid="1270732533356286514">"ascultă observații despre starea rețelei"</string>
     <string name="permdesc_accessNetworkConditions" msgid="2959269186741956109">"Permite unei aplicații să asculte observații despre starea rețelei. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
-    <string name="permlab_setInputCalibration" msgid="932069700285223434">"schimbați calibrarea dispozitivului de intrare"</string>
+    <string name="permlab_setInputCalibration" msgid="932069700285223434">"schimbă calibrarea dispozitivului de intrare"</string>
     <string name="permdesc_setInputCalibration" msgid="2937872391426631726">"Permite aplicației să modifice parametrii de calibrare a ecranului tactil. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_accessDrmCertificates" msgid="6473765454472436597">"accesează certificatele DRM"</string>
     <string name="permdesc_accessDrmCertificates" msgid="6983139753493781941">"Permite unei aplicații să furnizeze și să utilizeze certificate DRM. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
@@ -753,21 +753,21 @@
     <string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite proprietarului să pornească folosirea permisiunii pentru o aplicație. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"să înceapă să examineze deciziile privind permisiunile"</string>
     <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permite proprietarului să deschidă ecranul pentru a examina deciziile privind permisiunile. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
-    <string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"începeți să vedeți funcțiile aplicației"</string>
+    <string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"să vadă funcțiile aplicației"</string>
     <string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite proprietarului să înceapă să vadă informațiile despre funcții pentru o aplicație."</string>
     <string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"să acceseze date de la senzori la o rată de eșantionare mare"</string>
     <string name="permdesc_highSamplingRateSensors" msgid="8430061978931155995">"Permite aplicației să colecteze date de la senzori la o rată de eșantionare de peste 200 Hz"</string>
     <string name="policylab_limitPassword" msgid="4851829918814422199">"Să seteze reguli pentru parolă"</string>
-    <string name="policydesc_limitPassword" msgid="4105491021115793793">"Stabiliți lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
+    <string name="policydesc_limitPassword" msgid="4105491021115793793">"Stabilește lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
     <string name="policylab_watchLogin" msgid="7599669460083719504">"Să monitorizeze încercările de deblocare a ecranului"</string>
-    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
-    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați dispozitivul Android TV sau ștergeți toate datele de pe acesta dacă se introduc prea multe parole incorecte."</string>
-    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați sistemul de infotainment sau ștergeți toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin" product="tablet" msgid="2388436408621909298">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează tableta sau șterge datele acesteia dacă sunt introduse prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin" product="tv" msgid="2140588224468517507">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează dispozitivul Android TV sau șterge toate datele de pe acesta dacă se introduc prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin" product="automotive" msgid="7011438994051251521">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează sistemul de infotainment sau șterge toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
     <string name="policydesc_watchLogin" product="default" msgid="4885030206253600299">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează telefonul sau șterge toate datele acestuia dacă sunt introduse prea multe parole incorecte."</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați tableta sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați dispozitivul Android TV sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați sistemul de infotainment sau ștergeți toate datele acestui profil dacă sunt introduse prea multe parole incorecte."</string>
-    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Monitorizați numărul de parole incorecte introduse la deblocarea ecranului și blocați telefonul sau ștergeți toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează tableta sau șterge toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează dispozitivul Android TV sau șterge toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="automotive" msgid="7180857406058327941">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează sistemul de infotainment sau șterge toate datele acestui profil dacă sunt introduse prea multe parole incorecte."</string>
+    <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Monitorizează numărul de parole incorecte introduse la deblocarea ecranului și blochează telefonul sau șterge toate datele acestui utilizator dacă se introduc prea multe parole incorecte."</string>
     <string name="policylab_resetPassword" msgid="214556238645096520">"Să schimbe blocarea ecranului"</string>
     <string name="policydesc_resetPassword" msgid="4626419138439341851">"Modifică blocarea ecranului."</string>
     <string name="policylab_forceLock" msgid="7360335502968476434">"Să blocheze ecranul"</string>
@@ -923,7 +923,7 @@
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Apasă Meniu pentru deblocare."</string>
     <string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenează modelul pentru a debloca"</string>
     <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Urgență"</string>
-    <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Reveniți la apel"</string>
+    <string name="lockscreen_return_to_call" msgid="3156883574692006382">"Revino la apel"</string>
     <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corect!"</string>
     <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Încearcă din nou"</string>
     <string name="lockscreen_password_wrong" msgid="8605355913868947490">"Încearcă din nou"</string>
@@ -936,7 +936,7 @@
     <string name="lockscreen_missing_sim_instructions" msgid="8473601862688263903">"Introdu un card SIM."</string>
     <string name="lockscreen_missing_sim_instructions_long" msgid="3664999892038416334">"Cardul SIM lipsește sau nu poate fi citit. Introdu un card SIM."</string>
     <string name="lockscreen_permanent_disabled_sim_message_short" msgid="3812893366715730539">"Card SIM inutilizabil."</string>
-    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="4358929052509450807">"Cardul dvs. SIM este dezactivat definitiv.\n Contactați furnizorul de servicii wireless pentru a obține un alt card SIM."</string>
+    <string name="lockscreen_permanent_disabled_sim_instructions" msgid="4358929052509450807">"Cardul SIM este dezactivat definitiv.\n Contactează furnizorul de servicii wireless pentru a obține un alt card SIM."</string>
     <string name="lockscreen_transport_prev_description" msgid="2879469521751181478">"Melodia anterioară"</string>
     <string name="lockscreen_transport_next_description" msgid="2931509904881099919">"Melodia următoare"</string>
     <string name="lockscreen_transport_pause_description" msgid="6705284702135372494">"Pauză"</string>
@@ -947,31 +947,31 @@
     <string name="emergency_calls_only" msgid="3057351206678279851">"Numai apeluri de urgență"</string>
     <string name="lockscreen_network_locked_message" msgid="2814046965899249635">"Rețea blocată"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="6618356415831082174">"Cardul SIM este blocat cu codul PUK."</string>
-    <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consultați Ghidul de utilizare sau contactați Serviciul de relații cu clienții."</string>
+    <string name="lockscreen_sim_puk_locked_instructions" msgid="5307979043730860995">"Consultă Ghidul de utilizare sau contactează asistența pentru clienți."</string>
     <string name="lockscreen_sim_locked_message" msgid="3160196135801185938">"Cardul SIM este blocat."</string>
     <string name="lockscreen_sim_unlock_progress_dialog_message" msgid="2286497117428409709">"Se deblochează cardul SIM..."</string>
-    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g>   secunde."</string>
-    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Ați introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g>   secunde."</string>
+    <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6458790975898594240">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
+    <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="3118353451602377380">"Ai introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
     <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="2874278239714821984">"Ai introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
-    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul datelor de conectare la Google.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g>   secunde."</string>
+    <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi tableta cu ajutorul datelor de conectare la Google.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi dispozitivul Android TV prin conectarea la Google.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi telefonul cu ajutorul datelor de conectare la Google.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g>   secunde."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va reveni la setările din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a dispozitivului Android TV. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va reveni la setările din fabrică, iar toate datele de utilizator se vor pierde."</string>
-    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va fi acum resetată la setările prestabilite din fabrică."</string>
+    <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va reveni la setările din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va reveni acum la setările din fabrică."</string>
     <string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a dispozitivului Android TV. Acesta va reveni la setările din fabrică."</string>
-    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va fi acum resetat la setările prestabilite din fabrică."</string>
+    <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acesta va reveni acum la setările din fabrică."</string>
     <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"Încearcă din nou peste <xliff:g id="NUMBER">%d</xliff:g>   secunde."</string>
     <string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"Ai uitat modelul?"</string>
     <string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"Deblocare cont"</string>
     <string name="lockscreen_glogin_too_many_attempts" msgid="3775904917743034195">"Prea multe încercări de desenare a modelului"</string>
-    <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Pentru a debloca, conectați-vă folosind Contul Google."</string>
+    <string name="lockscreen_glogin_instructions" msgid="4695162942525531700">"Pentru a debloca, conectează-te 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">"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_account_recovery_hint" msgid="1683405808525090649">"Ai uitat numele de utilizator sau parola?\nAccesează "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Se verifică..."</string>
     <string name="lockscreen_unlock_label" msgid="4648257878373307582">"Deblochează"</string>
     <string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Sunet activat"</string>
@@ -1020,7 +1020,7 @@
     <string name="js_dialog_title_default" msgid="3769524569903332476">"JavaScript"</string>
     <string name="js_dialog_before_unload_title" msgid="7012587995876771246">"Confirmă părăsirea paginii"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="4274257182303565509">"Părăsește această pagină"</string>
-    <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"Rămâneți în această pagină"</string>
+    <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"Rămâi în această pagină"</string>
     <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur părăsești această pagină?"</string>
     <string name="save_password_label" msgid="9161712335355510035">"Confirmă"</string>
     <string name="double_tap_toast" msgid="7065519579174882778">"Sfat: mărește și micșorează prin dublă atingere."</string>
@@ -1055,7 +1055,7 @@
     <string name="permdesc_addVoicemail" msgid="5470312139820074324">"Permite aplicației să adauge mesaje în Mesaje primite în mesageria vocală."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"modificare permisiuni pentru locația geografică a browserului"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"Permite aplicației să modifice permisiunile privind locația geografică a browserului. Aplicațiile rău intenționate pot utiliza această permisiune pentru a permite trimiterea informațiilor privind locația către site-uri web arbitrare."</string>
-    <string name="save_password_message" msgid="2146409467245462965">"Doriți ca browserul să rețină această parolă?"</string>
+    <string name="save_password_message" msgid="2146409467245462965">"Vrei ca browserul să rețină această parolă?"</string>
     <string name="save_password_notnow" msgid="2878327088951240061">"Nu acum"</string>
     <string name="save_password_remember" msgid="6490888932657708341">"Reține"</string>
     <string name="save_password_never" msgid="6776808375903410659">"Niciodată"</string>
@@ -1084,7 +1084,7 @@
     <string name="searchview_description_clear" msgid="1989371719192982900">"Șterge interogarea"</string>
     <string name="searchview_description_submit" msgid="6771060386117334686">"Trimite interogarea"</string>
     <string name="searchview_description_voice" msgid="42360159504884679">"Căutare vocală"</string>
-    <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Activați Explorați prin atingere?"</string>
+    <string name="enable_explore_by_touch_warning_title" msgid="5095399706284943314">"Activezi Explorează prin atingere?"</string>
     <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="1037295476738940824">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> vrea să activeze funcția Explorează prin atingere. Când e activată, poți auzi sau vedea descrieri pentru ceea ce se află sub degetul tău sau poți face gesturi pentru a interacționa cu tableta."</string>
     <string name="enable_explore_by_touch_warning_message" product="default" msgid="4312979647356179250">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> dorește să activeze funcția Explorează prin atingere. Când aceasta e activată, poți auzi sau vedea descrieri pentru ceea ce se află sub degetul tău sau poți face gesturi pentru a interacționa cu telefonul."</string>
     <string name="oneMonthDurationPast" msgid="4538030857114635777">"cu 1 lună în urmă"</string>
@@ -1099,9 +1099,9 @@
     <string name="days" msgid="4570879797423034973">"   zile"</string>
     <string name="hour" msgid="7796325297097314653">"oră"</string>
     <string name="hours" msgid="8517014849629200683">"ore"</string>
-    <string name="minute" msgid="8369209540986467610">"min"</string>
+    <string name="minute" msgid="8369209540986467610">"min."</string>
     <string name="minutes" msgid="3456532942641808971">"min."</string>
-    <string name="second" msgid="9210875257112211713">"sec"</string>
+    <string name="second" msgid="9210875257112211713">"sec."</string>
     <string name="seconds" msgid="2175052687727971048">"sec."</string>
     <string name="week" msgid="907127093960923779">"săptămână"</string>
     <string name="weeks" msgid="3516247214269821391">"săptămâni"</string>
@@ -1126,7 +1126,7 @@
     <string name="duration_years_relative_future" msgid="8855853883925918380">"{count,plural, =1{# an}few{# ani}other{# de ani}}"</string>
     <string name="VideoView_error_title" msgid="5750686717225068016">"Problemă video"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3782449246085134720">"Acest fișier video nu este valid pentru a fi transmis în flux către acest dispozitiv."</string>
-    <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Nu puteți reda acest videoclip"</string>
+    <string name="VideoView_error_text_unknown" msgid="7658683339707607138">"Nu poți reda acest videoclip"</string>
     <string name="VideoView_error_button" msgid="5138809446603764272">"OK"</string>
     <string name="relative_time" msgid="8572030016028033243">"<xliff:g id="DATE">%1$s</xliff:g>, <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="noon" msgid="8365974533050605886">"prânz"</string>
@@ -1141,7 +1141,7 @@
     <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Eroare la copierea în clipboard"</string>
     <string name="paste" msgid="461843306215520225">"Inserează"</string>
     <string name="paste_as_plain_text" msgid="7664800665823182587">"Inserează ca text simplu"</string>
-    <string name="replace" msgid="7842675434546657444">"Înlocuiți..."</string>
+    <string name="replace" msgid="7842675434546657444">"Înlocuiește..."</string>
     <string name="delete" msgid="1514113991712129054">"Șterge"</string>
     <string name="copyUrl" msgid="6229645005987260230">"Copiază adresa URL"</string>
     <string name="selectTextMode" msgid="3225108910999318778">"Selectează text"</string>
@@ -1154,10 +1154,10 @@
     <string name="inputMethod" msgid="1784759500516314751">"Metodă de intrare"</string>
     <string name="editTextMenuTitle" msgid="857666911134482176">"Acțiuni pentru text"</string>
     <string name="input_method_nav_back_button_desc" msgid="3655838793765691787">"Înapoi"</string>
-    <string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Comutați metoda de introducere a textului"</string>
+    <string name="input_method_ime_switch_button_desc" msgid="2736542240252198501">"Schimbă metoda de introducere"</string>
     <string name="low_internal_storage_view_title" msgid="9024241779284783414">"Spațiul de stocare aproape ocupat"</string>
     <string name="low_internal_storage_view_text" msgid="8172166728369697835">"Este posibil ca unele funcții de sistem să nu funcționeze"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Spațiu de stocare insuficient pentru sistem. Asigurați-vă că aveți 250 MB de spațiu liber și reporniți."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"Spațiu de stocare insuficient pentru sistem. Asigură-te că ai 250 MB de spațiu liber și repornește."</string>
     <string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează acum"</string>
     <string name="app_running_notification_text" msgid="5120815883400228566">"Atinge pentru mai multe informații sau pentru a opri aplicația."</string>
     <string name="ok" msgid="2646370155170753815">"OK"</string>
@@ -1174,8 +1174,8 @@
     <string name="not_selected" msgid="410652016565864475">"neselectat"</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>
-    <string name="whichApplicationLabel" msgid="7852182961472531728">"Finalizați acțiunea"</string>
+    <string name="whichApplicationNamed" msgid="6969946041713975681">"Finalizează acțiunea folosind %1$s"</string>
+    <string name="whichApplicationLabel" msgid="7852182961472531728">"Finalizează acțiunea"</string>
     <string name="whichViewApplication" msgid="5733194231473132945">"Deschide cu"</string>
     <string name="whichViewApplicationNamed" msgid="415164730629690105">"Deschide cu %1$s"</string>
     <string name="whichViewApplicationLabel" msgid="7367556735684742409">"Deschide"</string>
@@ -1194,13 +1194,13 @@
     <string name="whichSendToApplicationNamed" msgid="3385686512014670003">"Trimite folosind %1$s"</string>
     <string name="whichSendToApplicationLabel" msgid="3543240188816513303">"Trimite"</string>
     <string name="whichHomeApplication" msgid="8276350727038396616">"Selectează o aplicație de pe ecranul de pornire"</string>
-    <string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Utilizați %1$s ca ecran de pornire"</string>
+    <string name="whichHomeApplicationNamed" msgid="5855990024847433794">"Folosește %1$s ca ecran de pornire"</string>
     <string name="whichHomeApplicationLabel" msgid="8907334282202933959">"Fotografiază"</string>
     <string name="whichImageCaptureApplication" msgid="2737413019463215284">"Fotografiază cu"</string>
     <string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"Fotografiază cu %1$s"</string>
     <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"Fotografiază"</string>
     <string name="alwaysUse" msgid="3153558199076112903">"Se utilizează în mod prestabilit pentru această acțiune."</string>
-    <string name="use_a_different_app" msgid="4987790276170972776">"Utilizați altă aplicație"</string>
+    <string name="use_a_different_app" msgid="4987790276170972776">"Folosește altă aplicație"</string>
     <string name="clearDefaultHintMsg" msgid="1325866337702524936">"Șterge setările prestabilite din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
     <string name="chooseActivity" msgid="8563390197659779956">"Alege o acțiune"</string>
     <string name="chooseUsbActivity" msgid="2096269989990986612">"Alege o aplicație pentru dispozitivul USB"</string>
@@ -1221,7 +1221,7 @@
     <string name="anr_application_process" msgid="4978772139461676184">"<xliff:g id="APPLICATION">%1$s</xliff:g> nu răspunde"</string>
     <string name="anr_process" msgid="1664277165911816067">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> nu răspunde"</string>
     <string name="force_close" msgid="9035203496368973803">"OK"</string>
-    <string name="report" msgid="2149194372340349521">"Raportați"</string>
+    <string name="report" msgid="2149194372340349521">"Raportează"</string>
     <string name="wait" msgid="7765985809494033348">"Așteaptă"</string>
     <string name="webpage_unresponsive" msgid="7850879412195273433">"Pagina a devenit inactivă.\n\nO închizi?"</string>
     <string name="launch_warning_title" msgid="6725456009564953595">"Aplicație redirecționată"</string>
@@ -1251,11 +1251,11 @@
     <string name="android_preparing_apk" msgid="589736917792300956">"Se pregătește <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"Se pornesc aplicațiile."</string>
     <string name="android_upgrading_complete" msgid="409800058018374746">"Se finalizează pornirea."</string>
-    <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Ați apăsat butonul de pornire. De obicei, această acțiune dezactivează ecranul.\n\nAtingeți ușor când vă configurați amprenta."</string>
+    <string name="fp_power_button_enrollment_message" msgid="5648173517663246140">"Ai apăsat butonul de pornire. De obicei, astfel se dezactivează ecranul.\n\nAtinge ușor când îți configurezi amprenta."</string>
     <string name="fp_power_button_enrollment_title" msgid="6976841690455338563">"Ca să termini configurarea, dezactivează ecranul"</string>
     <string name="fp_power_button_enrollment_button_text" msgid="3199783266386029200">"Dezactivează"</string>
-    <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Continuați cu verificarea amprentei?"</string>
-    <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Ați apăsat butonul de pornire. De obicei, această acțiune dezactivează ecranul.\n\nAtingeți ușor pentru verificarea amprentei."</string>
+    <string name="fp_power_button_bp_title" msgid="5585506104526820067">"Continui cu verificarea amprentei?"</string>
+    <string name="fp_power_button_bp_message" msgid="2983163038168903393">"Ai apăsat butonul de pornire. De obicei, astfel se dezactivează ecranul.\n\nAtinge ușor pentru verificarea amprentei."</string>
     <string name="fp_power_button_bp_positive_button" msgid="728945472408552251">"Dezactivează ecranul"</string>
     <string name="fp_power_button_bp_negative_button" msgid="3971364246496775178">"Continuă"</string>
     <string name="heavy_weight_notification" msgid="8382784283600329576">"Rulează <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -1270,8 +1270,8 @@
     <string name="dump_heap_notification_detail" msgid="8431586843001054050">"Datele privind memoria au fost culese. Atinge pentru a trimite."</string>
     <string name="dump_heap_title" msgid="4367128917229233901">"Trimiți datele privind memoria?"</string>
     <string name="dump_heap_text" msgid="1692649033835719336">"Procesul <xliff:g id="PROC">%1$s</xliff:g> și-a depășit limita de memorie de <xliff:g id="SIZE">%2$s</xliff:g>. Sunt disponibile datele privind memoria heap, pe care le poți trimite dezvoltatorului. Atenție: aceste date privind memoria heap pot conține informații cu caracter personal la care aplicația are acces."</string>
-    <string name="dump_heap_system_text" msgid="6805155514925350849">"Procesul <xliff:g id="PROC">%1$s</xliff:g> a depășit limita de memorie de <xliff:g id="SIZE">%2$s</xliff:g>. Sunt disponibile datele privind memoria heap, pe care le puteți distribui. Atenție: aceste date privind memoria heap pot conține informații cu caracter personal sensibile la care procesul are acces și care pot include ceea ce tastați."</string>
-    <string name="dump_heap_ready_text" msgid="5849618132123045516">"Sunt disponibile datele privind memoria heap a procesului <xliff:g id="PROC">%1$s</xliff:g>, pe care le puteți distribui. Atenție: aceste date privind memoria heap pot conține informații cu caracter personal sensibile la care procesul are acces și care pot include ceea ce tastați."</string>
+    <string name="dump_heap_system_text" msgid="6805155514925350849">"Procesul <xliff:g id="PROC">%1$s</xliff:g> a depășit limita de memorie de <xliff:g id="SIZE">%2$s</xliff:g>. Sunt disponibile datele privind memoria heap, pe care le poți distribui. Atenție: aceste date privind memoria heap pot conține informații cu caracter personal sensibile la care procesul are acces și care pot include ceea ce tastezi."</string>
+    <string name="dump_heap_ready_text" msgid="5849618132123045516">"Sunt disponibile datele privind memoria heap a procesului <xliff:g id="PROC">%1$s</xliff:g>, pe care le poți distribui. Atenție: aceste date privind memoria heap pot conține informații cu caracter personal sensibile la care procesul are acces și care pot include ceea ce tastezi."</string>
     <string name="sendText" msgid="493003724401350724">"Alege o acțiune pentru text"</string>
     <string name="volume_ringtone" msgid="134784084629229029">"Volum sonerie"</string>
     <string name="volume_music" msgid="7727274216734955095">"Volum media"</string>
@@ -1304,7 +1304,7 @@
     <string name="other_networks_no_internet" msgid="6698711684200067033">"Rețeaua nu are acces la internet"</string>
     <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Serverul DNS privat nu poate fi accesat"</string>
     <string name="network_partial_connectivity" msgid="4791024923851432291">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
-    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Atingeți pentru a vă conecta oricum"</string>
+    <string name="network_partial_connectivity_detailed" msgid="5741329444564575840">"Atinge pentru a te conecta oricum"</string>
     <string name="network_switch_metered" msgid="1531869544142283384">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="1358296010128405906">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
     <string name="network_switch_metered_toast" msgid="501662047275723743">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1316,7 +1316,7 @@
     <item msgid="9177085807664964627">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="3665696841646851068">"un tip de rețea necunoscut"</string>
-    <string name="accept" msgid="5447154347815825107">"Acceptați"</string>
+    <string name="accept" msgid="5447154347815825107">"Accept"</string>
     <string name="decline" msgid="6490507610282145874">"Refuz"</string>
     <string name="select_character" msgid="3352797107930786979">"Introdu caracterul"</string>
     <string name="sms_control_title" msgid="4748684259903148341">"Se trimit mesaje SMS"</string>
@@ -1328,18 +1328,18 @@
     <string name="sms_premium_short_code_details" msgid="1400296309866638111"><b>"Acest lucru va genera costuri în contul tău mobil."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="920477594325526691">"Trimite"</string>
     <string name="sms_short_code_confirm_deny" msgid="1356917469323768230">"Anulează"</string>
-    <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Doresc să se rețină opțiunea"</string>
+    <string name="sms_short_code_remember_choice" msgid="1374526438647744862">"Reține opțiunea"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="2620984439143080410">"Poți modifica ulterior în Setări &gt; Aplicații"</string>
     <string name="sms_short_code_confirm_always_allow" msgid="2223014893129755950">"Permite întotdeauna"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="2688828813521652079">"Nu permite niciodată"</string>
     <string name="sim_removed_title" msgid="5387212933992546283">"Card SIM eliminat"</string>
-    <string name="sim_removed_message" msgid="9051174064474904617">"Rețeaua mobilă va fi indisponibilă până când reporniți cu un card SIM valid introdus."</string>
+    <string name="sim_removed_message" msgid="9051174064474904617">"Rețeaua mobilă va fi indisponibilă până când repornești cu un card SIM valid introdus."</string>
     <string name="sim_done_button" msgid="6464250841528410598">"Terminat"</string>
     <string name="sim_added_title" msgid="7930779986759414595">"Card SIM adăugat"</string>
     <string name="sim_added_message" msgid="6602906609509958680">"Repornește dispozitivul pentru a accesa rețeaua mobilă."</string>
     <string name="sim_restart_button" msgid="8481803851341190038">"Repornește"</string>
     <string name="install_carrier_app_notification_title" msgid="5712723402213090102">"Activează serviciul mobil"</string>
-    <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Descărcați aplicația operatorului pentru a vă activa noul card SIM"</string>
+    <string name="install_carrier_app_notification_text" msgid="2781317581274192728">"Descarcă aplicația operatorului pentru a activa noul card SIM"</string>
     <string name="install_carrier_app_notification_text_app_name" msgid="4086877327264106484">"Descarcă aplicația <xliff:g id="APP_NAME">%1$s</xliff:g> pentru a-ți activa noul card SIM"</string>
     <string name="install_carrier_app_notification_button" msgid="6257740533102594290">"Descarcă aplicația"</string>
     <string name="carrier_app_notification_title" msgid="5815477368072060250">"S-a introdus un card SIM nou"</string>
@@ -1373,19 +1373,19 @@
     <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modul Set de testare este activat"</string>
     <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Revino la setările din fabrică pentru a dezactiva modul Set de testare."</string>
     <string name="console_running_notification_title" msgid="6087888939261635904">"Consola din serie este activată"</string>
-    <string name="console_running_notification_message" msgid="7892751888125174039">"Performanța este afectată. Pentru a dezactiva, verificați programul bootloader."</string>
+    <string name="console_running_notification_message" msgid="7892751888125174039">"Performanța este afectată. Pentru a dezactiva, verifică programul bootloader."</string>
     <string name="mte_override_notification_title" msgid="4731115381962792944">"MTE experimentală activată"</string>
-    <string name="mte_override_notification_message" msgid="2441170442725738942">"Performanța și stabilitatea pot fi afectate. Reporniți pentru a dezactiva. Dacă s-a activat cu arm64.memtag.bootctl, setați înainte la niciuna."</string>
+    <string name="mte_override_notification_message" msgid="2441170442725738942">"Performanța și stabilitatea pot fi afectate. Repornește pentru a dezactiva. Dacă s-a activat cu arm64.memtag.bootctl, setează dinainte la niciuna."</string>
     <string name="usb_contaminant_detected_title" msgid="4359048603069159678">"Lichide sau reziduuri în portul USB"</string>
-    <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"Portul USB este dezactivat automat. Atingeți ca să aflați mai multe."</string>
+    <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"Portul USB este dezactivat automat. Atinge ca să afli mai multe."</string>
     <string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"Portul USB poate fi folosit"</string>
     <string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"Telefonul nu mai detectează lichide sau reziduuri."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Se creează un raport de eroare…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"Trimiți raportul de eroare?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"Se trimite raportul de eroare…"</string>
-    <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Administratorul dvs. a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. Este posibil să se permită accesul la date și aplicații."</string>
-    <string name="share_remote_bugreport_action" msgid="7630880678785123682">"TRIMITEȚI"</string>
-    <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUZAȚI"</string>
+    <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"Administratorul a solicitat un raport de eroare pentru a remedia problemele acestui dispozitiv. E posibil să se permită accesul la date și aplicații."</string>
+    <string name="share_remote_bugreport_action" msgid="7630880678785123682">"TRIMITE"</string>
+    <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"REFUZ"</string>
     <string name="select_input_method" msgid="3971267998568587025">"Alege metoda de introducere de text"</string>
     <string name="show_ime" msgid="6406112007347443383">"Se păstrează pe ecran cât timp este activată tastatura fizică"</string>
     <string name="hardware" msgid="1800597768237606953">"Afișează tastatura virtuală"</string>
@@ -1396,7 +1396,7 @@
     <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"Afișare peste alte aplicații"</string>
     <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> se afișează peste alte aplicații"</string>
     <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> se afișează peste aplicații"</string>
-    <string name="alert_windows_notification_message" msgid="6538171456970725333">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
+    <string name="alert_windows_notification_message" msgid="6538171456970725333">"Dacă nu vrei ca <xliff:g id="NAME">%s</xliff:g> să folosească această funcție, atinge pentru a deschide setările și dezactiveaz-o."</string>
     <string name="alert_windows_notification_turn_off_action" msgid="7805857234839123780">"Dezactivează"</string>
     <string name="ext_media_checking_notification_title" msgid="8299199995416510094">"Se verifică <xliff:g id="NAME">%s</xliff:g>…"</string>
     <string name="ext_media_checking_notification_message" msgid="2231566971425375542">"Se examinează conținutul curent"</string>
@@ -1405,28 +1405,28 @@
     <string name="ext_media_new_notification_title" product="automotive" msgid="9085349544984742727">"<xliff:g id="NAME">%s</xliff:g> nu funcționează"</string>
     <string name="ext_media_new_notification_message" msgid="6095403121990786986">"Atinge pentru a configura"</string>
     <string name="ext_media_new_notification_message" product="tv" msgid="216863352100263668">"Selectează pentru a configura"</string>
-    <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"Poate fi nevoie să reformatați dispozitivul. Atingeți pentru a-l scoate."</string>
+    <string name="ext_media_new_notification_message" product="automotive" msgid="5140127881613227162">"Poate fi nevoie să reformatezi dispozitivul. Atinge pentru a-l scoate."</string>
     <string name="ext_media_ready_notification_message" msgid="7509496364380197369">"Pentru stocarea de fotografii, videoclipuri, muzică și altele"</string>
-    <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"Răsfoiți fișierele media"</string>
+    <string name="ext_media_ready_notification_message" product="tv" msgid="8847134811163165935">"Răsfoiește fișierele media"</string>
     <string name="ext_media_unmountable_notification_title" msgid="4895444667278979910">"Problemă cu <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unmountable_notification_title" product="automotive" msgid="3142723758949023280">"<xliff:g id="NAME">%s</xliff:g> nu funcționează"</string>
     <string name="ext_media_unmountable_notification_message" msgid="3256290114063126205">"Atinge pentru a remedia"</string>
     <string name="ext_media_unmountable_notification_message" product="tv" msgid="3003611129979934633">"<xliff:g id="NAME">%s</xliff:g> este corupt. Selectează pentru a remedia."</string>
-    <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"Poate fi nevoie să reformatați dispozitivul. Atingeți pentru a-l scoate."</string>
+    <string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"Poate fi nevoie să reformatezi dispozitivul. Atinge pentru a-l scoate."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3487534182861251401">"S-a detectat <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_unsupported_notification_title" product="automotive" msgid="6004193172658722381">"<xliff:g id="NAME">%s</xliff:g> nu funcționează"</string>
     <string name="ext_media_unsupported_notification_message" msgid="8463636521459807981">"Atinge pentru a configura"</string>
     <string name="ext_media_unsupported_notification_message" product="tv" msgid="1595482802187036532">"Selectează pentru a configura <xliff:g id="NAME">%s</xliff:g> într-un format acceptat."</string>
-    <string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"Poate fi nevoie să reformatați dispozitivul"</string>
+    <string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"Poate fi nevoie să reformatezi dispozitivul"</string>
     <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> scos pe neașteptate"</string>
     <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"Deconectează din setări dispozitivele media înainte de a le îndepărta, pentru a evita pierderea conținutului"</string>
     <string name="ext_media_nomedia_notification_title" msgid="742671636376975890">"S-a eliminat <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_nomedia_notification_message" msgid="2832724384636625852">"Funcționarea ar putea fi necorespunzătoare. Introdu un dispozitiv de stocare nou."</string>
     <string name="ext_media_unmounting_notification_title" msgid="4147986383917892162">"Se deconectează <xliff:g id="NAME">%s</xliff:g>"</string>
-    <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Nu scoateți"</string>
+    <string name="ext_media_unmounting_notification_message" msgid="5717036261538754203">"Nu scoate"</string>
     <string name="ext_media_init_action" msgid="2312974060585056709">"Configurează"</string>
     <string name="ext_media_unmount_action" msgid="966992232088442745">"Scoate"</string>
-    <string name="ext_media_browse_action" msgid="344865351947079139">"Explorați"</string>
+    <string name="ext_media_browse_action" msgid="344865351947079139">"Explorează"</string>
     <string name="ext_media_seamless_action" msgid="8837030226009268080">"Schimbă ieșirea"</string>
     <string name="ext_media_missing_title" msgid="3209472091220515046">"<xliff:g id="NAME">%s</xliff:g> lipsește"</string>
     <string name="ext_media_missing_message" msgid="4408988706227922909">"Reintrodu dispozitivul"</string>
@@ -1468,10 +1468,10 @@
     <string name="ime_action_next" msgid="4169702997635728543">"Înainte"</string>
     <string name="ime_action_done" msgid="6299921014822891569">"Terminat"</string>
     <string name="ime_action_previous" msgid="6548799326860401611">"Înapoi"</string>
-    <string name="ime_action_default" msgid="8265027027659800121">"Executați"</string>
-    <string name="dial_number_using" msgid="6060769078933953531">"Formați numărul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="create_contact_using" msgid="6200708808003692594">"Creați contactul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Următoarele aplicații solicită permisiunea de a accesa contul dvs. acum și în viitor."</string>
+    <string name="ime_action_default" msgid="8265027027659800121">"Execută"</string>
+    <string name="dial_number_using" msgid="6060769078933953531">"Formează numărul\nfolosind <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="create_contact_using" msgid="6200708808003692594">"Creează contactul\nutilizând <xliff:g id="NUMBER">%s</xliff:g>"</string>
+    <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"Următoarele aplicații solicită permisiunea de a-ți accesa contul acum și în viitor."</string>
     <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Permiți această solicitare?"</string>
     <string name="grant_permissions_header_text" msgid="3420736827804657201">"Solicitare de acces"</string>
     <string name="allow" msgid="6195617008611933762">"Permite"</string>
@@ -1509,12 +1509,12 @@
     <string name="next_button_label" msgid="6040209156399907780">"Înainte"</string>
     <string name="skip_button_label" msgid="3566599811326688389">"Omite"</string>
     <string name="no_matches" msgid="6472699895759164599">"Nicio potrivire"</string>
-    <string name="find_on_page" msgid="5400537367077438198">"Găsiți pe pagină"</string>
+    <string name="find_on_page" msgid="5400537367077438198">"Caută în pagină"</string>
     <string name="matches_found" msgid="2296462299979507689">"{count,plural, =1{# potrivire}few{# din {total}}other{# din {total}}}"</string>
     <string name="action_mode_done" msgid="2536182504764803222">"Terminat"</string>
     <string name="progress_erasing" msgid="6891435992721028004">"Se șterge spațiul de stocare distribuit..."</string>
     <string name="share" msgid="4157615043345227321">"Distribuie"</string>
-    <string name="find" msgid="5015737188624767706">"Găsiți"</string>
+    <string name="find" msgid="5015737188624767706">"Caută"</string>
     <string name="websearch" msgid="5624340204512793290">"Căutare pe web"</string>
     <string name="find_next" msgid="5341217051549648153">"Următorul rezultat"</string>
     <string name="find_previous" msgid="4405898398141275532">"Rezultatul anterior"</string>
@@ -1524,29 +1524,29 @@
     <string name="gpsVerifYes" msgid="3719843080744112940">"Da"</string>
     <string name="gpsVerifNo" msgid="1671201856091564741">"Nu"</string>
     <string name="sync_too_many_deletes" msgid="6999440774578705300">"Limita pentru ștergere a fost depășită"</string>
-    <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>   elemente șterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce doriți să faceți?"</string>
+    <string name="sync_too_many_deletes_desc" msgid="7409327940303504440">"Există <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g>   elemente șterse pentru <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>, contul <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>. Ce vrei să faci?"</string>
     <string name="sync_really_delete" msgid="5657871730315579051">"Șterge elementele"</string>
     <string name="sync_undo_deletes" msgid="5786033331266418896">"Anulează aceste ștergeri"</string>
-    <string name="sync_do_nothing" msgid="4528734662446469646">"Nu trebuie să luați nicio măsură deocamdată"</string>
+    <string name="sync_do_nothing" msgid="4528734662446469646">"Nu trebuie să iei nicio măsură deocamdată"</string>
     <string name="choose_account_label" msgid="5557833752759831548">"Alege un cont"</string>
     <string name="add_account_label" msgid="4067610644298737417">"Adaugă un cont"</string>
     <string name="add_account_button_label" msgid="322390749416414097">"Adaugă un cont"</string>
-    <string name="number_picker_increment_button" msgid="7621013714795186298">"Creșteți"</string>
-    <string name="number_picker_decrement_button" msgid="5116948444762708204">"Reduceți"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> atingeți lung."</string>
+    <string name="number_picker_increment_button" msgid="7621013714795186298">"Mărește"</string>
+    <string name="number_picker_decrement_button" msgid="5116948444762708204">"Redu"</string>
+    <string name="number_picker_increment_scroll_mode" msgid="8403893549806805985">"<xliff:g id="VALUE">%s</xliff:g> atinge lung."</string>
     <string name="number_picker_increment_scroll_action" msgid="8310191318914268271">"Glisează în sus pentru a crește și în jos pentru a reduce."</string>
-    <string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Creșteți valoarea pentru minute"</string>
+    <string name="time_picker_increment_minute_button" msgid="7195870222945784300">"Mărește valoarea pentru minute"</string>
     <string name="time_picker_decrement_minute_button" msgid="230925389943411490">"Redu valoarea pentru minute"</string>
-    <string name="time_picker_increment_hour_button" msgid="3063572723197178242">"Creșteți valoarea pentru oră"</string>
+    <string name="time_picker_increment_hour_button" msgid="3063572723197178242">"Mărește valoarea pentru oră"</string>
     <string name="time_picker_decrement_hour_button" msgid="584101766855054412">"Redu valoarea pentru oră"</string>
     <string name="time_picker_increment_set_pm_button" msgid="5889149366900376419">"Setează valoarea PM"</string>
     <string name="time_picker_decrement_set_am_button" msgid="1422608001541064087">"Setează valoarea AM"</string>
     <string name="date_picker_increment_month_button" msgid="3447263316096060309">"Mărește valoarea pentru lună"</string>
-    <string name="date_picker_decrement_month_button" msgid="6531888937036883014">"Reduceți valoarea pentru lună"</string>
+    <string name="date_picker_decrement_month_button" msgid="6531888937036883014">"Redu valoarea pentru lună"</string>
     <string name="date_picker_increment_day_button" msgid="4349336637188534259">"Mărește valoarea pentru zi"</string>
-    <string name="date_picker_decrement_day_button" msgid="6840253837656637248">"Reduceți valoarea pentru zi"</string>
-    <string name="date_picker_increment_year_button" msgid="7608128783435372594">"Creșteți valoarea pentru an"</string>
-    <string name="date_picker_decrement_year_button" msgid="4102586521754172684">"Reduceți valoarea pentru an"</string>
+    <string name="date_picker_decrement_day_button" msgid="6840253837656637248">"Redu valoarea pentru zi"</string>
+    <string name="date_picker_increment_year_button" msgid="7608128783435372594">"Mărește valoarea pentru an"</string>
+    <string name="date_picker_decrement_year_button" msgid="4102586521754172684">"Redu valoarea pentru an"</string>
     <string name="date_picker_prev_month_button" msgid="3418694374017868369">"Luna trecută"</string>
     <string name="date_picker_next_month_button" msgid="4858207337779144840">"Luna viitoare"</string>
     <string name="keyboardview_keycode_alt" msgid="8997420058584292385">"Alt"</string>
@@ -1560,7 +1560,7 @@
     <string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Nu s-a putut lansa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="shareactionprovider_share_with" msgid="2753089758467748982">"Permite accesul pentru"</string>
     <string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Permite accesul pentru <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="content_description_sliding_handle" msgid="982510275422590757">"Mâner glisant. Atingeți și țineți apăsat."</string>
+    <string name="content_description_sliding_handle" msgid="982510275422590757">"Ghidaj glisant. Atinge și ține apăsat."</string>
     <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Glisează pentru a debloca."</string>
     <string name="action_bar_home_description" msgid="1501655419158631974">"Navighează la ecranul de pornire"</string>
     <string name="action_bar_up_description" msgid="6611579697195026932">"Navighează în sus"</string>
@@ -1644,59 +1644,59 @@
     <string name="kg_sim_pin_instructions" msgid="6479401489471690359">"Introdu codul PIN al cardului SIM"</string>
     <string name="kg_pin_instructions" msgid="7355933174673539021">"Introdu codul PIN"</string>
     <string name="kg_password_instructions" msgid="7179782578809398050">"Introdu parola"</string>
-    <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"Cardul SIM este acum dezactivat. Introduceți codul PUK pentru a continua. Contactați operatorul pentru mai multe detalii."</string>
+    <string name="kg_puk_enter_puk_hint" msgid="6696187482616360994">"Cardul SIM este acum dezactivat. Introdu codul PUK pentru a continua. Contactează operatorul pentru mai multe detalii."</string>
     <string name="kg_puk_enter_pin_hint" msgid="8190982314659429770">"Introdu codul PIN dorit"</string>
     <string name="kg_enter_confirm_pin_hint" msgid="6372557107414074580">"Confirmă codul PIN dorit"</string>
     <string name="kg_sim_unlock_progress_dialog_message" msgid="8871937892678885545">"Se deblochează cardul SIM..."</string>
     <string name="kg_password_wrong_pin_code" msgid="9013856346870572451">"Cod PIN incorect."</string>
     <string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"Introdu un cod PIN format din 4 până la 8 cifre."</string>
     <string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"Codul PUK trebuie să conțină 8 numere."</string>
-    <string name="kg_invalid_puk" msgid="4809502818518963344">"Reintroduceți codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
+    <string name="kg_invalid_puk" msgid="4809502818518963344">"Reintrodu codul PUK corect. Încercările repetate vor dezactiva definitiv cardul SIM."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Codurile PIN nu coincid"</string>
     <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Prea multe încercări de desenare a modelului"</string>
-    <string name="kg_login_instructions" msgid="3619844310339066827">"Pentru a debloca, conectați-vă cu Contul dvs. Google."</string>
+    <string name="kg_login_instructions" msgid="3619844310339066827">"Pentru a debloca, conectează-te folosind Contul 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">"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_account_recovery_hint" msgid="4892466171043541248">"Ai uitat numele de utilizator sau parola?\nAccesează "<b>"google.com/accounts/recovery"</b>"."</string>
     <string name="kg_login_checking_password" msgid="4676010303243317253">"Se verifică contul…"</string>
-    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Ați introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g>   secunde."</string>
+    <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"Ai introdus incorect codul PIN de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori.\n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Ai introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
-    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncercați din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g>   secunde."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va reveni la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, aceasta va reveni la setările din fabrică, iar toate datele de utilizator se vor pierde."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a dispozitivului Android TV. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va reveni la setările din fabrică, iar toate datele de utilizator se vor pierde."</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va fi resetat la setările prestabilite din fabrică, iar toate datele de utilizator se vor pierde."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"Ați făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va reveni acum la setările din fabrică."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acesta va reveni la setările din fabrică, iar toate datele de utilizator se vor pierde."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Tableta va reveni acum la setările din fabrică."</string>
     <string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a dispozitivului Android TV. Acesta va reveni la setările din fabrică."</string>
-    <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va fi acum resetat la setările prestabilite din fabrică."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g>   secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați dispozitivul Android TV cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+    <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Telefonul va reveni acum la setările din fabrică."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi tableta cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi dispozitivul Android TV cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi telefonul cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Elimină"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
-    <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string>
-    <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Atunci când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de trei secunde, veți lansa o funcție de accesibilitate."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mărești volumul peste nivelul recomandat?\n\nDacă asculți perioade lungi la volum ridicat, auzul poate fi afectat."</string>
+    <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Folosești comanda rapidă pentru accesibilitate?"</string>
+    <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Când comanda rapidă e activată, dacă apeși ambele butoane de volum timp de trei secunde, vei lansa o funcție de accesibilitate."</string>
     <string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activezi comanda rapidă pentru funcțiile de accesibilitate?"</string>
-    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Dacă apăsați ambele taste de volum câteva secunde, activați funcțiile de accesibilitate. Acest lucru poate schimba funcționarea dispozitivului.\n\nFuncțiile actuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuteți schimba funcțiile selectate din Setări &gt; Accesibilitate."</string>
+    <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Dacă apeși ambele taste de volum câteva secunde, activezi funcțiile de accesibilitate. Acest lucru poate schimba funcționarea dispozitivului.\n\nFuncțiile actuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPoți schimba funcțiile selectate din Setări &gt; Accesibilitate."</string>
     <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
     <string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activezi comanda rapidă <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
-    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Dacă apăsați ambele taste de volum câteva secunde, activați funcția de accesibilitate <xliff:g id="SERVICE">%1$s</xliff:g>. Acest lucru poate schimba funcționarea dispozitivului.\n\nPuteți alege altă funcție pentru această comandă în Setări &gt; Accesibilitate."</string>
+    <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Dacă apeși ambele taste de volum câteva secunde, activezi funcția de accesibilitate <xliff:g id="SERVICE">%1$s</xliff:g>. Acest lucru poate schimba funcționarea dispozitivului.\n\nPoți alege altă funcție pentru această comandă în Setări &gt; Accesibilitate."</string>
     <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activează"</string>
-    <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nu activați"</string>
+    <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Nu activa"</string>
     <string name="accessibility_shortcut_menu_item_status_on" msgid="6608392117189732543">"ACTIVAT"</string>
     <string name="accessibility_shortcut_menu_item_status_off" msgid="5531598275559472393">"DEZACTIVAT"</string>
-    <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Permiteți serviciului <xliff:g id="SERVICE">%1$s</xliff:g> să aibă control total asupra dispozitivului dvs.?"</string>
-    <string name="accessibility_service_warning_description" msgid="291674995220940133">"Controlul total este adecvat pentru aplicații care vă ajută cu accesibilitatea, însă nu pentru majoritatea aplicaților."</string>
-    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Vă vede și vă controlează ecranul"</string>
+    <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Permiți serviciului <xliff:g id="SERVICE">%1$s</xliff:g> să aibă control total asupra dispozitivului?"</string>
+    <string name="accessibility_service_warning_description" msgid="291674995220940133">"Controlul total este adecvat pentru aplicații care te ajută cu accesibilitatea, însă nu pentru majoritatea aplicaților."</string>
+    <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"să vadă și să controleze ecranul"</string>
     <string name="accessibility_service_screen_control_description" msgid="6946315917771791525">"Poate citi tot conținutul de pe ecran și poate afișa conținut peste alte aplicații."</string>
-    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"Vă vede interacțiunile și le realizează"</string>
-    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Poate urmări interacțiunile dvs. cu o aplicație sau cu un senzor hardware și poate interacționa cu aplicații în numele dvs."</string>
+    <string name="accessibility_service_action_perform_title" msgid="779670378951658160">"să vadă și să facă acțiuni"</string>
+    <string name="accessibility_service_action_perform_description" msgid="2718852014003170558">"Poate să urmărească interacțiunile tale cu o aplicație sau cu un senzor hardware și să interacționeze cu aplicații în numele tău."</string>
     <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"Permite"</string>
     <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"Refuz"</string>
-    <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Atingeți o funcție ca să începeți să o folosiți:"</string>
-    <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Alegeți funcțiile pe care să le folosiți cu butonul de accesibilitate"</string>
+    <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"Atinge o funcție ca să începi să o folosești:"</string>
+    <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"Alege funcțiile pe care să le folosești cu butonul de accesibilitate"</string>
     <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"Alege funcțiile pentru comanda rapidă a butonului de volum"</string>
     <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> a fost dezactivat"</string>
     <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"Editează comenzile rapide"</string>
@@ -1710,12 +1710,12 @@
     <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"S-au apăsat lung tastele de volum. S-a activat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"S-au apăsat lung tastele de volum. S-a dezactivat <xliff:g id="SERVICE_NAME">%1$s</xliff:g>."</string>
     <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"Apasă ambele butoane de volum timp de trei secunde pentru a folosi <xliff:g id="SERVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Alegeți o funcție pe care să o folosiți când atingeți butonul de accesibilitate:"</string>
-    <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Alegeți o funcție pe care să o folosiți cu gestul de accesibilitate (glisați în sus cu două degete din partea de jos a ecranului):"</string>
-    <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Alegeți o funcție pe care să o folosiți cu gestul de accesibilitate (glisați în sus cu trei degete din partea de jos a ecranului):"</string>
-    <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Pentru a comuta între funcții, atingeți lung butonul de accesibilitate."</string>
-    <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Pentru a comuta între funcții, glisați în sus cu două degete și mențineți apăsat."</string>
-    <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Pentru a comuta între funcții, glisați în sus cu trei degete și mențineți apăsat."</string>
+    <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"Alege o funcție pe care să o folosești când atingi butonul de accesibilitate:"</string>
+    <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"Alege o funcție pe care să o folosești cu gestul de accesibilitate (glisează în sus cu două degete din partea de jos a ecranului):"</string>
+    <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"Alege o funcție pe care să o folosești cu gestul de accesibilitate (glisează în sus cu trei degete din partea de jos a ecranului):"</string>
+    <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"Pentru a comuta între funcții, atinge lung butonul de accesibilitate."</string>
+    <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"Pentru a comuta între funcții, glisează în sus cu două degete și ține apăsat."</string>
+    <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"Pentru a comuta între funcții, glisează în sus cu trei degete și ține apăsat."</string>
     <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"Mărire"</string>
     <string name="user_switched" msgid="7249833311585228097">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Se comută la <xliff:g id="NAME">%1$s</xliff:g>…"</string>
@@ -1725,7 +1725,7 @@
     <string name="error_message_title" msgid="4082495589294631966">"Eroare"</string>
     <string name="error_message_change_not_allowed" msgid="843159705042381454">"Această modificare nu este permisă de administrator"</string>
     <string name="app_not_found" msgid="3429506115332341800">"Nicio aplicație pentru gestionarea acestei acțiuni"</string>
-    <string name="revoke" msgid="5526857743819590458">"Revocați"</string>
+    <string name="revoke" msgid="5526857743819590458">"Revocă"</string>
     <string name="mediasize_iso_a0" msgid="7039061159929977973">"ISO A0"</string>
     <string name="mediasize_iso_a1" msgid="4063589931031977223">"ISO A1"</string>
     <string name="mediasize_iso_a2" msgid="2779860175680233980">"ISO A2"</string>
@@ -1833,12 +1833,12 @@
     <string name="restr_pin_enter_old_pin" msgid="7537079094090650967">"Codul PIN actual"</string>
     <string name="restr_pin_enter_new_pin" msgid="3267614461844565431">"Codul PIN nou"</string>
     <string name="restr_pin_confirm_pin" msgid="7143161971614944989">"Confirmă noul cod PIN"</string>
-    <string name="restr_pin_create_pin" msgid="917067613896366033">"Creați un cod PIN pentru modificarea restricțiilor"</string>
-    <string name="restr_pin_error_doesnt_match" msgid="7063392698489280556">"Codurile PIN nu se potrivesc. Încercați din nou."</string>
+    <string name="restr_pin_create_pin" msgid="917067613896366033">"Creează un cod PIN pentru modificarea restricțiilor"</string>
+    <string name="restr_pin_error_doesnt_match" msgid="7063392698489280556">"PIN-urile nu sunt identice. Încearcă din nou."</string>
     <string name="restr_pin_error_too_short" msgid="1547007808237941065">"Codul PIN este prea scurt. Trebuie să aibă cel puțin 4 cifre."</string>
     <string name="restr_pin_try_later" msgid="5897719962541636727">"Reîncearcă mai târziu"</string>
     <string name="immersive_cling_title" msgid="2307034298721541791">"Vizualizare pe ecran complet"</string>
-    <string name="immersive_cling_description" msgid="7092737175345204832">"Pentru a ieși, glisați de sus în jos."</string>
+    <string name="immersive_cling_description" msgid="7092737175345204832">"Pentru a ieși, glisează de sus în jos."</string>
     <string name="immersive_cling_positive" msgid="7047498036346489883">"Am înțeles"</string>
     <string name="done_label" msgid="7283767013231718521">"Terminat"</string>
     <string name="hour_picker_description" msgid="5153757582093524635">"Selector circular pentru ore"</string>
@@ -1856,7 +1856,7 @@
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicită parola înainte de a anula fixarea"</string>
     <string name="package_installed_device_owner" msgid="7035926868974878525">"Instalat de administrator"</string>
     <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administrator"</string>
-    <string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administratorul dvs."</string>
+    <string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Economisirea bateriei activează tema întunecată și restricționează sau dezactivează activitatea în fundal, unele efecte vizuale, alte funcții și câteva conexiuni la rețea."</string>
     <string name="battery_saver_description" msgid="8518809702138617167">"Economisirea bateriei activează tema întunecată și restricționează sau dezactivează activitatea în fundal, unele efecte vizuale, alte funcții și câteva conexiuni la rețea."</string>
@@ -1874,8 +1874,8 @@
     <string name="zen_mode_until_next_day" msgid="1403042784161725038">"Până <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_until" msgid="2250286190237669079">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_alarm" msgid="7046911727540499275">"Până la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (următoarea alarmă)"</string>
-    <string name="zen_mode_forever" msgid="740585666364912448">"Până când dezactivați"</string>
-    <string name="zen_mode_forever_dnd" msgid="3423201955704180067">"Până când dezactivați „Nu deranja”"</string>
+    <string name="zen_mode_forever" msgid="740585666364912448">"Până dezactivezi"</string>
+    <string name="zen_mode_forever_dnd" msgid="3423201955704180067">"Până când dezactivezi „Nu deranja”"</string>
     <string name="zen_mode_rule_name_combination" msgid="7174598364351313725">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
     <string name="toolbar_collapse_description" msgid="8009920446193610996">"Restrânge"</string>
     <string name="zen_mode_feature_name" msgid="3785547207263754500">"Nu deranja"</string>
@@ -1907,13 +1907,13 @@
     <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"Port USB periferic"</string>
     <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"Mai multe opțiuni"</string>
     <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"Închide meniul suplimentar"</string>
-    <string name="maximize_button_text" msgid="4258922519914732645">"Maximizați"</string>
+    <string name="maximize_button_text" msgid="4258922519914732645">"Maximizează"</string>
     <string name="close_button_text" msgid="10603510034455258">"Închide"</string>
     <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
     <string name="call_notification_answer_action" msgid="5999246836247132937">"Răspunde"</string>
     <string name="call_notification_answer_video_action" msgid="2086030940195382249">"Video"</string>
-    <string name="call_notification_decline_action" msgid="3700345945214000726">"Respingeți"</string>
-    <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Încheiați"</string>
+    <string name="call_notification_decline_action" msgid="3700345945214000726">"Respinge"</string>
+    <string name="call_notification_hang_up_action" msgid="9130720590159188131">"Închide"</string>
     <string name="call_notification_incoming_text" msgid="6143109825406638201">"Apel primit"</string>
     <string name="call_notification_ongoing_text" msgid="3880832933933020875">"Apel în desfășurare"</string>
     <string name="call_notification_screening_text" msgid="8396931408268940208">"Se filtrează un apel primit"</string>
@@ -1937,7 +1937,7 @@
     <string name="app_suspended_more_details" msgid="211260942831587014">"Află mai multe"</string>
     <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulează întreruperea aplicației"</string>
     <string name="work_mode_off_title" msgid="961171256005852058">"Activezi aplicațiile pentru lucru?"</string>
-    <string name="work_mode_off_message" msgid="7319580997683623309">"Obțineți acces la aplicațiile pentru lucru și notificări"</string>
+    <string name="work_mode_off_message" msgid="7319580997683623309">"Obține acces la aplicațiile și notificările pentru lucru"</string>
     <string name="work_mode_turn_on" msgid="3662561662475962285">"Activează"</string>
     <string name="app_blocked_title" msgid="7353262160455028160">"Aplicația nu este disponibilă"</string>
     <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu este disponibilă momentan."</string>
@@ -1959,17 +1959,17 @@
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Nu se poate accesa pe <xliff:g id="DEVICE">%1$s</xliff:g>. Încearcă pe dispozitivul Android TV."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Nu se poate accesa pe <xliff:g id="DEVICE">%1$s</xliff:g>. Încearcă pe tabletă."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Nu se poate accesa pe <xliff:g id="DEVICE">%1$s</xliff:g>. Încearcă pe telefon."</string>
-    <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Această aplicație a fost creată pentru o versiune Android mai veche și este posibil să nu funcționeze corect. Încercați să căutați actualizări sau contactați dezvoltatorul."</string>
+    <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Această aplicație a fost creată pentru o versiune Android mai veche și e posibil să nu funcționeze corect. Încearcă să cauți actualizări sau contactează dezvoltatorul."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Caută actualizări"</string>
-    <string name="new_sms_notification_title" msgid="6528758221319927107">"Aveți mesaje noi"</string>
+    <string name="new_sms_notification_title" msgid="6528758221319927107">"Ai mesaje noi"</string>
     <string name="new_sms_notification_content" msgid="3197949934153460639">"Deschide aplicația pentru SMS-uri ca să vezi"</string>
     <string name="profile_encrypted_title" msgid="9001208667521266472">"Unele funcții ar putea fi limitate"</string>
     <string name="profile_encrypted_detail" msgid="5279730442756849055">"Profil de serviciu blocat"</string>
     <string name="profile_encrypted_message" msgid="1128512616293157802">"Atinge ca să deblochezi"</string>
     <string name="usb_mtp_launch_notification_title" msgid="774319638256707227">"Conectat la <xliff:g id="PRODUCT_NAME">%1$s</xliff:g>"</string>
     <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Atinge pentru a vedea fișierele"</string>
-    <string name="pin_target" msgid="8036028973110156895">"Fixați"</string>
-    <string name="pin_specific_target" msgid="7824671240625957415">"Fixați <xliff:g id="LABEL">%1$s</xliff:g>"</string>
+    <string name="pin_target" msgid="8036028973110156895">"Fixează"</string>
+    <string name="pin_specific_target" msgid="7824671240625957415">"Fixează <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="unpin_target" msgid="3963318576590204447">"Anulează fixarea"</string>
     <string name="unpin_specific_target" msgid="3859828252160908146">"Anulează fixarea pentru <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="app_info" msgid="6113278084877079851">"Informații despre aplicație"</string>
@@ -1995,7 +1995,7 @@
     <string name="time_picker_header_text" msgid="9073802285051516688">"Setează ora"</string>
     <string name="time_picker_input_error" msgid="8386271930742451034">"Introdu o oră validă"</string>
     <string name="time_picker_prompt_label" msgid="303588544656363889">"Introdu ora"</string>
-    <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Pentru a introduce ora, comutați la modul de introducere a textului."</string>
+    <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"Pentru a introduce ora, comută la modul de introducere a textului."</string>
     <string name="time_picker_radial_mode_description" msgid="1222342577115016953">"Pentru a introduce ora, comută la modul ceas."</string>
     <string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"Opțiuni de completare automată"</string>
     <string name="autofill_save_accessibility_title" msgid="1523225776218450005">"Salvează pentru completare automată"</string>
@@ -2024,9 +2024,9 @@
     <string name="autofill_save_type_generic_card" msgid="1019367283921448608">"card"</string>
     <string name="autofill_save_type_username" msgid="1018816929884640882">"nume de utilizator"</string>
     <string name="autofill_save_type_email_address" msgid="1303262336895591924">"adresă de e-mail"</string>
-    <string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"Păstrați-vă calmul și căutați un adăpost în apropiere."</string>
-    <string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"Părăsiți imediat zonele de coastă și din apropierea râurilor și îndreptați-vă spre un loc mai sigur, cum ar fi o zonă aflată la înălțime."</string>
-    <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"Păstrați-vă calmul și căutați un adăpost în apropiere."</string>
+    <string name="etws_primary_default_message_earthquake" msgid="8401079517718280669">"Păstrează-ți calmul și caută un adăpost în apropiere."</string>
+    <string name="etws_primary_default_message_tsunami" msgid="5828171463387976279">"Părăsește imediat zonele de coastă și din apropierea râurilor și îndreaptă-te spre un loc mai sigur, cum ar fi o zonă aflată la înălțime."</string>
+    <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="4888224011071875068">"Păstrează-ți calmul și caută un adăpost în apropiere."</string>
     <string name="etws_primary_default_message_test" msgid="4583367373909549421">"Testarea mesajelor de urgență"</string>
     <string name="notification_reply_button_accessibility" msgid="5235776156579456126">"Răspunde"</string>
     <string name="etws_primary_default_message_others" msgid="7958161706019130739"></string>
@@ -2045,13 +2045,14 @@
     <string name="shortcut_restore_signature_mismatch" msgid="579345304221605479">"Nu s-a putut restabili comanda rapidă din cauza nepotrivirii semnăturii aplicației"</string>
     <string name="shortcut_restore_unknown_issue" msgid="2478146134395982154">"Nu s-a putut restabili comanda rapidă"</string>
     <string name="shortcut_disabled_reason_unknown" msgid="753074793553599166">"Comanda rapidă este dezactivată"</string>
-    <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEZINSTALAȚI"</string>
+    <string name="harmful_app_warning_uninstall" msgid="6472912975664191772">"DEZINSTALEAZĂ"</string>
     <string name="harmful_app_warning_open_anyway" msgid="5963657791740211807">"Deschide oricum"</string>
     <string name="harmful_app_warning_title" msgid="8794823880881113856">"Aplicație dăunătoare detectată"</string>
     <string name="log_access_confirmation_title" msgid="2343578467290592708">"Permiț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 accesul o dată"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nu permite"</string>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Jurnalele dispozitivului înregistrează activitatea de pe acesta. 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. E posibil ca producătorul dispozitivului să acceseze în continuare unele jurnale sau informații de pe dispozitiv.\n\nAflă mai multe la g.co/android/devicelogs."</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">"Editează"</string>
@@ -2060,11 +2061,11 @@
     <string name="notification_channel_system_changes" msgid="2462010596920209678">"Modificări de sistem"</string>
     <string name="notification_channel_do_not_disturb" msgid="7832584281883687653">"Nu deranja"</string>
     <string name="zen_upgrade_notification_visd_title" msgid="2001148984371968620">"Funcția nouă Nu deranja ascunde notificările"</string>
-    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Atingeți ca să aflați mai multe și să modificați"</string>
+    <string name="zen_upgrade_notification_visd_content" msgid="3683314609114134946">"Atinge ca să afli mai multe și să modifici"</string>
     <string name="zen_upgrade_notification_title" msgid="8198167698095298717">"Funcția Nu deranja s-a schimbat"</string>
     <string name="zen_upgrade_notification_content" msgid="5228458567180124005">"Atinge pentru a verifica ce este blocat."</string>
-    <string name="review_notification_settings_title" msgid="5102557424459810820">"Examinați setările pentru notificări"</string>
-    <string name="review_notification_settings_text" msgid="5916244866751849279">"Începând cu Android 13, aplicațiile pe care le instalați necesită permisiunea de a trimite notificări. Atingeți ca să modificați permisiunea pentru aplicațiile existente."</string>
+    <string name="review_notification_settings_title" msgid="5102557424459810820">"Verifică setările pentru notificări"</string>
+    <string name="review_notification_settings_text" msgid="5916244866751849279">"Începând cu Android 13, aplicațiile pe care le instalezi necesită permisiunea de a trimite notificări. Atinge ca să modifici permisiunea pentru aplicațiile existente."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"Mai târziu"</string>
     <string name="review_notification_settings_dismiss" msgid="4160916504616428294">"Închide"</string>
     <string name="notification_app_name_system" msgid="3045196791746735601">"Sistem"</string>
@@ -2072,7 +2073,7 @@
     <string name="notification_appops_camera_active" msgid="8177643089272352083">"Cameră foto"</string>
     <string name="notification_appops_microphone_active" msgid="581333393214739332">"Microfon"</string>
     <string name="notification_appops_overlay_active" msgid="5571732753262836481">"se afișează peste alte aplicații de pe ecran"</string>
-    <string name="notification_feedback_indicator" msgid="663476517711323016">"Oferiți feedback"</string>
+    <string name="notification_feedback_indicator" msgid="663476517711323016">"Oferă feedback"</string>
     <string name="notification_feedback_indicator_alerted" msgid="6552871804121942099">"Notificarea a fost promovată la Prestabilită. Atinge pentru a oferi feedback."</string>
     <string name="notification_feedback_indicator_silenced" msgid="3799442124723177262">"Notificarea a fost mutată în jos la Silențioasă. Atinge pentru a oferi feedback."</string>
     <string name="notification_feedback_indicator_promoted" msgid="9030204303764698640">"Notificarea a fost mutată la un nivel superior. Atinge pentru a oferi feedback."</string>
@@ -2082,7 +2083,7 @@
     <string name="nas_upgrade_notification_enable_action" msgid="3046406808378726874">"OK"</string>
     <string name="nas_upgrade_notification_disable_action" msgid="3794833210043497982">"Dezactivează"</string>
     <string name="nas_upgrade_notification_learn_more_action" msgid="7011130656195423947">"Află mai multe"</string>
-    <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Notificările optimizate au înlocuit Notificările adaptive Android de pe Android 12. Această funcție afișează acțiuni și răspunsuri sugerate și vă organizează notificările.\n\nNotificările optimizate pot accesa conținutul notificărilor, inclusiv informații cu caracter personal, precum mesajele și numele persoanelor de contact. În plus, funcția poate să închidă sau să răspundă la notificări, de exemplu, să răspundă la apeluri telefonice și să gestioneze opțiunea Nu deranja."</string>
+    <string name="nas_upgrade_notification_learn_more_content" msgid="3735480566983530650">"Notificările optimizate au înlocuit Notificările adaptive Android de pe Android 12. Această funcție afișează acțiuni și răspunsuri sugerate și organizează notificările.\n\nNotificările optimizate pot accesa conținutul notificărilor, inclusiv informații cu caracter personal, precum mesajele și numele persoanelor de contact. În plus, funcția poate să închidă sau să răspundă la notificări, de exemplu, să răspundă la apeluri telefonice și să gestioneze opțiunea Nu deranja."</string>
     <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Notificare pentru informații despre modul Rutină"</string>
     <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Bateria se poate descărca înainte de încărcarea obișnuită"</string>
     <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Economisirea bateriei este activată pentru a mări autonomia"</string>
@@ -2270,9 +2271,9 @@
     <string name="config_pdp_reject_service_not_subscribed" msgid="8190338397128671588"></string>
     <string name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" msgid="6024904218067254186"></string>
     <string name="window_magnification_prompt_title" msgid="2876703640772778215">"Noi setări de mărire"</string>
-    <string name="window_magnification_prompt_content" msgid="8159173903032344891">"Acum puteți mări o parte a ecranului"</string>
+    <string name="window_magnification_prompt_content" msgid="8159173903032344891">"Acum poți mări o parte a ecranului"</string>
     <string name="turn_on_magnification_settings_action" msgid="8521433346684847700">"Activează din Setări"</string>
-    <string name="dismiss_action" msgid="1728820550388704784">"Respingeți"</string>
+    <string name="dismiss_action" msgid="1728820550388704784">"Închide"</string>
     <string name="sensor_privacy_start_use_mic_notification_content_title" msgid="2420858361276370367">"Deblochează microfonul dispozitivului"</string>
     <string name="sensor_privacy_start_use_camera_notification_content_title" msgid="7287720213963466672">"Deblochează camera dispozitivului"</string>
     <string name="sensor_privacy_start_use_notification_content_text" msgid="7595608891015777346">"Pentru &lt;b&gt;<xliff:g id="APP">%s</xliff:g>&lt;/b&gt; și toate aplicațiile și serviciile"</string>
@@ -2280,8 +2281,8 @@
     <string name="sensor_privacy_notification_channel_label" msgid="936036783155261349">"Confidențialitatea privind senzorii"</string>
     <string name="splash_screen_view_icon_description" msgid="180638751260598187">"Pictograma aplicației"</string>
     <string name="splash_screen_view_branding_description" msgid="7911129347402728216">"Imaginea de branding a aplicației"</string>
-    <string name="view_and_control_notification_title" msgid="4300765399209912240">"Verificați setările pentru acces"</string>
-    <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> poate să vadă și să vă controleze ecranul. Atingeți pentru a examina."</string>
+    <string name="view_and_control_notification_title" msgid="4300765399209912240">"Verifică setările pentru acces"</string>
+    <string name="view_and_control_notification_content" msgid="8003766498562604034">"<xliff:g id="SERVICE_NAME">%s</xliff:g> poate să vadă și să controleze ecranul. Atinge pentru a verifica."</string>
     <string name="ui_translation_accessibility_translated_text" msgid="3197547218178944544">"<xliff:g id="MESSAGE">%1$s</xliff:g> a fost tradus."</string>
     <string name="ui_translation_accessibility_translation_finished" msgid="3057830947610088465">"Mesaj tradus din <xliff:g id="FROM_LANGUAGE">%1$s</xliff:g> în <xliff:g id="TO_LANGUAGE">%2$s</xliff:g>."</string>
     <string name="notification_channel_abusive_bg_apps" msgid="6092140213264920355">"Activitate de fundal"</string>
@@ -2289,7 +2290,7 @@
     <string name="notification_title_long_running_fgs" msgid="8170284286477131587">"O aplicație este încă activă"</string>
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> rulează în fundal. Atinge pentru a gestiona utilizarea bateriei."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> poate afecta autonomia bateriei. Atinge pentru a examina aplicațiile active."</string>
-    <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verificați aplicațiile active"</string>
+    <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Verifică aplicațiile active"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nu se poate accesa camera foto a telefonului de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nu se poate accesa camera foto a tabletei de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Nu se poate accesa în timpul streamingului. Încearcă pe telefon."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 2ccf54f..86115d5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -2052,7 +2052,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"В журналы записывается информация о том, что происходит на устройстве. Приложения могут использовать их, чтобы находить и устранять неполадки.\n\nТак как некоторые журналы могут содержать конфиденциальную информацию, доступ ко всем журналам следует предоставлять только тем приложениям, которым вы доверяете. \n\nЕсли вы не предоставите такой доступ этому приложению, оно по-прежнему сможет просматривать свои журналы. Не исключено, что некоторые журналы или сведения на вашем устройстве будут по-прежнему доступны его производителю."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"В журналы записывается информация о том, что происходит на устройстве. Приложения могут использовать их, чтобы находить и устранять неполадки.\n\nТак как некоторые журналы могут содержать конфиденциальную информацию, доступ ко всем журналам следует предоставлять только тем приложениям, которым вы доверяете. \n\nЕсли вы не предоставите такой доступ этому приложению, оно по-прежнему сможет просматривать свои журналы. Не исключено, что некоторые журналы или сведения на вашем устройстве будут по-прежнему доступны его производителю."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"В журналы записывается информация о том, что происходит на устройстве. Приложения могут использовать их, чтобы находить и устранять неполадки.\n\nТак как некоторые журналы могут содержать конфиденциальную информацию, доступ ко всем журналам следует предоставлять только тем приложениям, которым вы доверяете. \n\nЕсли вы не предоставите такой доступ этому приложению, оно по-прежнему сможет просматривать свои журналы. Также некоторые журналы или сведения на вашем устройстве могут быть доступны его производителю.\n\nПодробнее: g.co/android/devicelogs."</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>
@@ -2291,7 +2292,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"\"<xliff:g id="APP">%1$s</xliff:g>\" работает в фоновом режиме. Нажмите, чтобы изменить настройки, связанные с расходом заряда батареи."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"Приложение \"<xliff:g id="APP">%1$s</xliff:g>\" может влиять на время работы батареи. Нажмите, чтобы увидеть активные приложения."</string>
     <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="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>
     <string name="vdm_secure_window" msgid="161700398158812314">"Этот контент недоступен во время трансляции. Используйте телефон."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Системные настройки по умолчанию"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 3d1a441..76f6608 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"උපාංග ලොග ඔබේ උපාංගයෙහි සිදු වන දේ වාර්තා කරයි. ගැටලු සොයා ගැනීමට සහ නිරාකරණයට යෙදුම්වලට මෙම ලොග භාවිතා කළ හැක.\n\nසමහර ලොගවල සංවේදී තතු අඩංගු විය හැකි බැවින්, ඔබ විශ්වාස කරන යෙදුම්වලට පමණක් සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න. \n\nඔබ මෙම යෙදුමට සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ නොදෙන්නේ නම්, එයට තවමත් එහිම ලොග වෙත ප්‍රවේශ විය හැක. ඔබේ උපාංග නිෂ්පාදකයාට තවමත් ඔබේ උපාංගයෙහි සමහර ලොග හෝ තතු වෙත ප්‍රවේශ විය හැක."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"උපාංග ලොග ඔබේ උපාංගයෙහි සිදු වන දේ වාර්තා කරයි. ගැටලු සොයා ගැනීමට සහ නිරාකරණයට යෙදුම්වලට මෙම ලොග භාවිතා කළ හැක.\n\nසමහර ලොගවල සංවේදී තතු අඩංගු විය හැකි බැවින්, ඔබ විශ්වාස කරන යෙදුම්වලට පමණක් සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න. \n\nඔබ මෙම යෙදුමට සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ නොදෙන්නේ නම්, එයට තවමත් එහිම ලොග වෙත ප්‍රවේශ විය හැක. ඔබේ උපාංග නිෂ්පාදකයාට තවමත් ඔබේ උපාංගයෙහි සමහර ලොග හෝ තතු වෙත ප්‍රවේශ විය හැක."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"උපාංග ලොග ඔබේ උපාංගයෙහි සිදු වන දේ වාර්තා කරයි. ගැටලු සොයා ගැනීමට සහ නිරාකරණයට යෙදුම්වලට මෙම ලොග භාවිතා කළ හැක.\n\nසමහර ලොගවල සංවේදී තතු අඩංගු විය හැකි බැවින්, ඔබ විශ්වාස කරන යෙදුම්වලට පමණක් සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ දෙන්න. \n\nඔබ මෙම යෙදුමට සියලු උපාංග ලොග වෙත ප්‍රවේශ වීමට ඉඩ නොදෙන්නේ නම්, එයට තවමත් එහිම ලොග වෙත ප්‍රවේශ විය හැක. ඔබේ උපාංග නිෂ්පාදකයාට තවමත් ඔබේ උපාංගයෙහි සමහර ලොග හෝ තතු වෙත ප්‍රවේශ විය හැක.\n\ng.co/android/devicelogs හි දී තව දැන ගන්න."</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-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c2f906e..898126e 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1953,13 +1953,13 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Nastavenia telefónu nie sú k dispozícii"</string>
     <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť zariadenie Android TV."</string>
     <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť tablet."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste namiesto toho použiť telefón."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte k tomuto obsahu prístup. Skúste použiť telefón."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste namiesto toho použiť zariadenie Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste namiesto toho použiť tablet."</string>
-    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste namiesto toho použiť telefón."</string>
+    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Táto aplikácia požaduje dodatočné zabezpečenie. Skúste použiť telefón."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte prístup k tomuto obsahu. Skúste namiesto toho použiť zariadenie Android TV."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte prístup k tomuto obsahu. Skúste namiesto toho použiť tablet."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte prístup k tomuto obsahu. Skúste namiesto toho použiť telefón."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> momentálne nemáte prístup k tomuto obsahu. Skúste použiť telefón."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Táto aplikácia bola zostavená pre staršiu verziu Androidu a nemusí správne fungovať. Skúste skontrolovať dostupnosť aktualizácií alebo kontaktovať vývojára."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Skontrolovať dostupnosť aktualizácie"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Máte nové správy."</string>
@@ -2052,7 +2052,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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í.\n\nViac sa dozviete na g.co/android/devicelogs."</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>
@@ -2293,6 +2294,6 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Skontrolovať aktívne aplikácie"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere telefónu"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere tabletu"</string>
-    <string name="vdm_secure_window" msgid="161700398158812314">"K tomuto obsahu nie je počas streamovania prístup. Skúste namiesto toho použiť telefón."</string>
+    <string name="vdm_secure_window" msgid="161700398158812314">"K tomuto obsahu nie je počas streamovania prístup. Skúste použiť telefón."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predvolené systémom"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 9e6c571..a5cd174 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -2052,7 +2052,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nPreberite več o tem na g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index dee3691..9ef7770 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nMëso më shumë në g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 0a5c4c0..4747297 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2051,7 +2051,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају.\n\nСазнајте више на g.co/android/devicelogs."</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 7eabd55..d7675f5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Enhetsloggar registrerar 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.\n\nLäs mer på g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index ae2e801..5a7538e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"Kumbukumbu za kifaa hurekodi 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.\n\nPata maelezo zaidi kwenye g.co/android/devicelogs."</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>
@@ -2289,7 +2290,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> inatumika chinichini. Gusa ili udhibiti matumizi ya betri."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> inaweza kuathiri muda wa matumizi ya betri. Gusa ili ukague programu zinazotumika."</string>
     <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="default" msgid="6102378580971542473">"Huwezi 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>
     <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>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 507bafb..b08b86b 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸ் இந்தப் பதிவுகளைப் பயன்படுத்தலாம்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள் சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக நீங்கள் நம்பும் ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸ் இந்தப் பதிவுகளைப் பயன்படுத்தலாம்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள் சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக நீங்கள் நம்பும் ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸால் இந்தப் பதிவுகளைப் பயன்படுத்த முடியும்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள், சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக உங்களுக்கு நம்பகமான ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை நீங்கள் அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்.\n\n மேலும் அறிந்துகொள்ள g.co/android/devicelogs இணைப்பிற்குச் செல்லுங்கள்."</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 47e3deb..131ccd0 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్‌లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్‌లు ఈ లాగ్‌లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్‌లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్‌లను మాత్రమే అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్‌ను అనుమతించకపోతే, అది తన స్వంత లాగ్‌లను ఇప్పటికి యాక్సెస్ చేయగలదు. మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్‌లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్‌లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్‌లు ఈ లాగ్‌లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్‌లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్‌లను మాత్రమే అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్‌ను అనుమతించకపోతే, అది తన స్వంత లాగ్‌లను ఇప్పటికి యాక్సెస్ చేయగలదు. మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్‌లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"మీ పరికరంలో జరిగే దాన్ని పరికర లాగ్‌లు రికార్డ్ చేస్తాయి. సమస్యలను కనుగొని, పరిష్కరించడానికి యాప్‌లు ఈ లాగ్‌లను ఉపయోగిస్తాయి.\n\nకొన్ని లాగ్‌లలో గోప్యమైన సమాచారం ఉండవచ్చు, కాబట్టి మీరు విశ్వసించే యాప్‌లను మాత్రమే అన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి అనుమతించండి. \n\nఅన్ని పరికర లాగ్‌లను యాక్సెస్ చేయడానికి మీరు ఈ యాప్‌ను అనుమతించకపోతే, అది తన స్వంత లాగ్‌లను ఇప్పటికి యాక్సెస్ చేయగలదు. మీ పరికర తయారీదారు ఇప్పటికీ మీ పరికరంలో కొన్ని లాగ్‌లు లేదా సమాచారాన్ని యాక్సెస్ చేయగలరు.\n\ng.co/android/devicelogsలో దీని గురించి మరింత తెలుసుకోండి."</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 2d2e172..6af5165 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ \n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ของคุณได้"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ \n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ของคุณได้"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์\n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ได้\n\nดูข้อมูลเพิ่มเติมที่ g.co/android/devicelogs"</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 298239e..7bb0ba9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nMatuto pa sa g.co/android/devicelogs."</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 7e308bd..27183f2 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nDaha fazla bilgiyi g.co/android/devicelogs sayfasında bulabilirsiniz."</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>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index d07ed8b..d2485c7 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -2052,7 +2052,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"У журналах пристрою реєструється все, що відбувається на ньому. За допомогою цих журналів додатки можуть виявляти й усувати проблеми.\n\nДеякі журнали можуть містити конфіденційні дані, тому надавати доступ до всіх журналів пристрою слід лише надійним додаткам. \n\nЯкщо додаток не має доступу до всіх журналів пристрою, він усе одно може використовувати власні журнали. Виробник вашого пристрою все одно може використовувати деякі журнали чи інформацію на ньому."</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"У журналах пристрою реєструється все, що відбувається на ньому. За допомогою цих журналів додатки можуть виявляти й усувати проблеми.\n\nДеякі журнали можуть містити конфіденційні дані, тому надавати доступ до всіх журналів пристрою слід лише надійним додаткам. \n\nЯкщо додаток не має доступу до всіх журналів пристрою, він усе одно може використовувати власні журнали. Виробник вашого пристрою все одно може використовувати деякі журнали чи інформацію на ньому."</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"У журналах пристрою реєструється все, що відбувається на ньому. За допомогою цих журналів додатки можуть виявляти й усувати проблеми.\n\nДеякі журнали можуть містити конфіденційні дані, тому надавати доступ до всіх журналів пристрою слід лише надійним додаткам. \n\nЯкщо додаток не має доступу до всіх журналів пристрою, він усе одно може використовувати власні журнали. Виробник вашого пристрою все одно може використовувати деякі журнали чи інформацію на ньому.\n\nДокладніше: g.co/android/devicelogs."</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-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2520a94..9d9bb1a 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"آپ کے آلے پر جو ہوتا ہے آلے کے لاگز اسے ریکارڈ کر لیتے ہیں۔ ایپس ان لاگز کا استعمال مسائل کو تلاش کرنے اور ان کو حل کرنے کے لیے کر سکتی ہیں۔\n\nکچھ لاگز میں حساس معلومات شامل ہو سکتی ہیں، اس لیے صرف اپنے بھروسے مند ایپس کو ہی آلے کے تمام لاگز تک رسائی کی اجازت دیں۔ \n\nاگر آپ اس ایپ کو آلے کے تمام لاگز تک رسائی کی اجازت نہیں دیتے ہیں تب بھی یہ اپنے لاگز تک رسائی حاصل کر سکتی ہے۔ آپ کے آلے کا مینوفیکچرر اب بھی آپ کے آلے پر کچھ لاگز یا معلومات تک رسائی حاصل کر سکتا ہے۔"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"آپ کے آلے پر جو ہوتا ہے آلے کے لاگز اسے ریکارڈ کر لیتے ہیں۔ ایپس ان لاگز کا استعمال مسائل کو تلاش کرنے اور ان کو حل کرنے کے لیے کر سکتی ہیں۔\n\nکچھ لاگز میں حساس معلومات شامل ہو سکتی ہیں، اس لیے صرف اپنے بھروسے مند ایپس کو ہی آلے کے تمام لاگز تک رسائی کی اجازت دیں۔ \n\nاگر آپ اس ایپ کو آلے کے تمام لاگز تک رسائی کی اجازت نہیں دیتے ہیں تب بھی یہ اپنے لاگز تک رسائی حاصل کر سکتی ہے۔ آپ کے آلے کا مینوفیکچرر اب بھی آپ کے آلے پر کچھ لاگز یا معلومات تک رسائی حاصل کر سکتا ہے۔"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"‏آپ کے آلے پر جو ہوتا ہے آلے کے لاگز اسے ریکارڈ کر لیتے ہیں۔ ایپس ان لاگز کا استعمال مسائل کو تلاش کرنے اور ان کو حل کرنے کے لیے کر سکتی ہیں۔\n\nکچھ لاگز میں حساس معلومات شامل ہو سکتی ہیں، اس لیے صرف اپنی بھروسے مند ایپس کو ہی آلے کے تمام لاگز تک رسائی کی اجازت دیں۔ \n\nاگر آپ اس ایپ کو آلے کے تمام لاگز تک رسائی کی اجازت نہیں دیتے ہیں تب بھی یہ اپنے لاگز تک رسائی حاصل کر سکتی ہے۔ آپ کے آلے کا مینوفیکچرر اب بھی آپ کے آلے پر کچھ لاگز یا معلومات تک رسائی حاصل کر سکتا ہے۔\n\ng.co/android/devicelogs پر مزید جانیں۔"</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 ba7138f..bad432d 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nBatafsil: g.co/android/devicelogs."</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 dc4c005..66f0bdd 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1233,7 +1233,7 @@
     <string name="unsupported_display_size_show" msgid="980129850974919375">"Luôn hiển thị"</string>
     <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> được xây dựng cho phiên bản không tương thích của hệ điều hành Android và có thể hoạt động không như mong đợi. Bạn có thể sử dụng phiên bản cập nhật của ứng dụng."</string>
     <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Luôn hiển thị"</string>
-    <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Kiểm tra bản cập nhật"</string>
+    <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Kiểm tra để tìm bản cập nhật"</string>
     <string name="smv_application" msgid="3775183542777792638">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
     <string name="smv_process" msgid="1398801497130695446">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
     <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Điện thoại đang cập nhật…"</string>
@@ -1959,7 +1959,7 @@
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên máy tính bảng."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên điện thoại."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ứng dụng này được xây dựng cho một phiên bản Android cũ hơn và có thể hoạt động không bình thường. Hãy thử kiểm tra các bản cập nhật hoặc liên hệ với nhà phát triển."</string>
-    <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra bản cập nhật"</string>
+    <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra để tìm bản cập nhật"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Bạn có tin nhắn mới"</string>
     <string name="new_sms_notification_content" msgid="3197949934153460639">"Mở ứng dụng SMS để xem"</string>
     <string name="profile_encrypted_title" msgid="9001208667521266472">"Một số chức năng có thể bị hạn chế"</string>
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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 các 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 mọi 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.\n\nTìm hiểu thêm tại g.co/android/devicelogs."</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>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f830731..d46bdc8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,它仍然可以访问自己的日志。您的设备制造商可能仍然能够访问设备上的部分日志或信息。"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,它仍然可以访问自己的日志。您的设备制造商可能仍然能够访问设备上的部分日志或信息。"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"设备日志会记录设备上发生的活动。应用可以使用这些日志查找和修复问题。\n\n部分日志可能包含敏感信息,因此请仅允许您信任的应用访问所有设备日志。\n\n如果您不授予此应用访问所有设备日志的权限,它仍然可以访问自己的日志。您的设备制造商可能仍然能够访问设备上的部分日志或信息。\n\n如需了解详情,请访问 g.co/android/devicelogs。"</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 3ffffdc..81a0413 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -651,9 +651,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_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_roll_too_extreme" msgid="8261939882838881194">"請正面望向手機"</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) -->
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"裝置記錄會記下裝置上的活動。應用程式可透過這些記錄找出並修正問題。\n\n部分記錄可能包含敏感資料,因此請只允許信任的應用程式存取所有裝置記錄。\n\n如果不允許此應用程式存取所有裝置記錄,此應用程式仍能存取自己的記錄,且裝置製造商可能仍可存取裝置上的部分記錄或資料。"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"裝置記錄會記下裝置上的活動。應用程式可透過這些記錄找出並修正問題。\n\n部分記錄可能包含敏感資料,因此請只允許信任的應用程式存取所有裝置記錄。\n\n如果不允許此應用程式存取所有裝置記錄,此應用程式仍能存取自己的記錄,且裝置製造商可能仍可存取裝置上的部分記錄或資料。"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"裝置記錄會記下裝置上的活動。應用程式可使用這些記錄找出並修正問題。\n\n有些記錄可能包含敏感資料,因此建議只允許信任的應用程式存取所有裝置記錄。\n\n如果不允許此應用程式存取所有裝置記錄,此應用程式仍能存取自己的記錄。您的裝置製造商可能仍可存取裝置上的一些記錄或資料。\n\n詳情請瀏覽 g.co/android/devicelogs。"</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 9698053..43de5ba 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <string name="log_access_confirmation_body" msgid="1806692062668620735">"系統會透過裝置記錄記下裝置上的活動。應用程式可以根據這些記錄找出問題並進行修正。\n\n某些記錄可能含有機密資訊,因此請勿讓不信任的應用程式存取所有裝置記錄。\n\n即使你不允許這個應用程式存取所有裝置記錄,這個應用程式仍能存取自己的記錄,而且裝置製造商或許仍可存取裝置的某些記錄或資訊。"</string>
+    <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"系統會透過裝置記錄記下裝置上的活動。應用程式可以根據這些記錄找出問題並進行修正。\n\n某些記錄可能含有機密資訊,因此請勿讓不信任的應用程式存取所有裝置記錄。\n\n即使你不允許這個應用程式存取所有裝置記錄,這個應用程式仍能存取自己的記錄,而且裝置製造商或許仍可存取裝置的某些記錄或資訊。"</string>
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"裝置記錄會記下裝置上的活動。應用程式可以根據這些記錄找出問題並進行修正。\n\n由於某些記錄可能含有機密資訊,建議只讓信任的應用程式存取所有裝置記錄。\n\n如果你不允許這個應用程式存取所有裝置記錄,這個應用程式仍可存取屬於自己的記錄,而裝置製造商也或許還是可以存取裝置的某些記錄或資訊。\n\n請參閱以下網址瞭解詳情:g.co/android/devicelogs。"</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 539c02a..22a7110 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -2050,7 +2050,8 @@
     <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>
-    <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_confirmation_body" product="default" 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_confirmation_body" product="tv" msgid="7379536536425265262">"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.\n\nFunda kabanzi ku-g.co/android/devicelogs."</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/config.xml b/core/res/res/values/config.xml
index 5d1acbc..3408f75 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -553,6 +553,14 @@
     <!-- If this is true, then keep dreaming when undocking. -->
     <bool name="config_keepDreamingWhenUndocking">false</bool>
 
+    <!-- The timeout (in ms) to wait before attempting to reconnect to the dream overlay service if
+         it becomes disconnected -->
+    <integer name="config_dreamOverlayReconnectTimeoutMs">1000</integer> <!-- 1 second -->
+    <!-- The maximum number of times to attempt reconnecting to the dream overlay service -->
+    <integer name="config_dreamOverlayMaxReconnectAttempts">3</integer>
+    <!-- The duration after which the dream overlay connection should be considered stable -->
+    <integer name="config_minDreamOverlayDurationMs">10000</integer> <!-- 10 seconds -->
+
     <!-- Auto-rotation behavior -->
 
     <!-- If true, enables auto-rotation features using the accelerometer.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6e574bd..16798b8 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2239,6 +2239,9 @@
   <java-symbol type="array" name="config_supportedDreamComplications" />
   <java-symbol type="array" name="config_disabledDreamComponents" />
   <java-symbol type="bool" name="config_dismissDreamOnActivityStart" />
+  <java-symbol type="integer" name="config_dreamOverlayReconnectTimeoutMs" />
+  <java-symbol type="integer" name="config_dreamOverlayMaxReconnectAttempts" />
+  <java-symbol type="integer" name="config_minDreamOverlayDurationMs" />
   <java-symbol type="string" name="config_loggable_dream_prefix" />
   <java-symbol type="string" name="config_dozeComponent" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
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/com/android/internal/app/ResolverWrapperAdapter.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java
index 56a7070..2861428 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java
@@ -46,14 +46,14 @@
     }
 
     @Override
-    protected LoadLabelTask getLoadLabelTask(DisplayResolveInfo info, ViewHolder holder) {
-        return new LoadLabelWrapperTask(info, holder);
+    protected LoadLabelTask createLoadLabelTask(DisplayResolveInfo info) {
+        return new LoadLabelWrapperTask(info);
     }
 
     class LoadLabelWrapperTask extends LoadLabelTask {
 
-        protected LoadLabelWrapperTask(DisplayResolveInfo dri, ViewHolder holder) {
-            super(dri, holder);
+        protected LoadLabelWrapperTask(DisplayResolveInfo dri) {
+            super(dri);
         }
 
         @Override
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
index fd4fb13..2719431 100644
--- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
@@ -17,7 +17,6 @@
 package com.android.internal.util;
 
 import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
-import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
 
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.fail;
@@ -85,12 +84,6 @@
     }
 
     @Test
-    public void testSelectedRegionScreenshot() {
-        mScreenshotHelper.takeScreenshot(TAKE_SCREENSHOT_SELECTED_REGION,
-                WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null);
-    }
-
-    @Test
     public void testProvidedImageScreenshot() {
         mScreenshotHelper.provideScreenshot(
                 new Bundle(), new Rect(), Insets.of(0, 0, 0, 0), 1, 1, new ComponentName("", ""),
diff --git a/core/tests/utiltests/Android.bp b/core/tests/utiltests/Android.bp
index adc3676..3798da5 100644
--- a/core/tests/utiltests/Android.bp
+++ b/core/tests/utiltests/Android.bp
@@ -34,6 +34,7 @@
         "mockito-target-minus-junit4",
         "androidx.test.ext.junit",
         "truth-prebuilt",
+        "servicestests-utils",
     ],
 
     libs: [
diff --git a/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java b/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java
new file mode 100644
index 0000000..d124ad9
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/ObservableServiceConnectionTest.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.ObservableServiceConnection.ServiceTransformer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayDeque;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+
+@SmallTest
+public class ObservableServiceConnectionTest {
+    private static final ComponentName COMPONENT_NAME =
+            new ComponentName("test.package", "component");
+
+    public static class Foo {
+        int mValue;
+
+        Foo(int value) {
+            mValue = value;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Foo)) return false;
+            Foo foo = (Foo) o;
+            return mValue == foo.mValue;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mValue);
+        }
+    }
+
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Intent mIntent;
+    @Mock
+    private Foo mResult;
+    @Mock
+    private IBinder mBinder;
+    @Mock
+    private ServiceTransformer<Foo> mTransformer;
+    @Mock
+    private ObservableServiceConnection.Callback<Foo> mCallback;
+    private final FakeExecutor mExecutor = new FakeExecutor();
+    private ObservableServiceConnection<Foo> mConnection;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        mConnection = new ObservableServiceConnection<>(
+                mContext,
+                mExecutor,
+                mTransformer,
+                mIntent,
+                /* flags= */ Context.BIND_AUTO_CREATE);
+    }
+
+    @After
+    public void tearDown() {
+        mExecutor.clearAll();
+    }
+
+    @Test
+    public void testConnect() {
+        // Register twice to ensure only one callback occurs.
+        mConnection.addCallback(mCallback);
+        mConnection.addCallback(mCallback);
+
+        mExecutor.runAll();
+        mConnection.bind();
+
+        // Ensure that no callbacks happen before connection.
+        verify(mCallback, never()).onConnected(any(), any());
+        verify(mCallback, never()).onDisconnected(any(), anyInt());
+
+        when(mTransformer.convert(mBinder)).thenReturn(mResult);
+        mConnection.onServiceConnected(COMPONENT_NAME, mBinder);
+
+        mExecutor.runAll();
+        verify(mCallback, times(1)).onConnected(mConnection, mResult);
+    }
+
+    @Test
+    public void testDisconnectBeforeBind() {
+        mConnection.addCallback(mCallback);
+        mExecutor.runAll();
+        mConnection.onServiceDisconnected(COMPONENT_NAME);
+        mExecutor.runAll();
+        // Disconnects before binds should be ignored.
+        verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt());
+    }
+
+    @Test
+    public void testDisconnect() {
+        mConnection.addCallback(mCallback);
+        mExecutor.runAll();
+        mConnection.bind();
+        mConnection.onServiceDisconnected(COMPONENT_NAME);
+
+        // Ensure the callback doesn't get triggered until the executor runs.
+        verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt());
+        mExecutor.runAll();
+        // Ensure proper disconnect reason reported.
+        verify(mCallback, times(1)).onDisconnected(mConnection,
+                ObservableServiceConnection.DISCONNECT_REASON_DISCONNECTED);
+        // Verify unbound from service.
+        verify(mContext, times(1)).unbindService(mConnection);
+
+        clearInvocations(mContext);
+        // Ensure unbind after disconnect has no effect on the connection
+        mConnection.unbind();
+        verify(mContext, never()).unbindService(mConnection);
+    }
+
+    @Test
+    public void testBindingDied() {
+        mConnection.addCallback(mCallback);
+        mExecutor.runAll();
+        mConnection.bind();
+        mConnection.onBindingDied(COMPONENT_NAME);
+
+        // Ensure the callback doesn't get triggered until the executor runs.
+        verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt());
+        mExecutor.runAll();
+        // Ensure proper disconnect reason reported.
+        verify(mCallback, times(1)).onDisconnected(mConnection,
+                ObservableServiceConnection.DISCONNECT_REASON_BINDING_DIED);
+        // Verify unbound from service.
+        verify(mContext, times(1)).unbindService(mConnection);
+    }
+
+    @Test
+    public void testNullBinding() {
+        mConnection.addCallback(mCallback);
+        mExecutor.runAll();
+        mConnection.bind();
+        mConnection.onNullBinding(COMPONENT_NAME);
+
+        // Ensure the callback doesn't get triggered until the executor runs.
+        verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt());
+        mExecutor.runAll();
+        // Ensure proper disconnect reason reported.
+        verify(mCallback, times(1)).onDisconnected(mConnection,
+                ObservableServiceConnection.DISCONNECT_REASON_NULL_BINDING);
+        // Verify unbound from service.
+        verify(mContext, times(1)).unbindService(mConnection);
+    }
+
+    @Test
+    public void testUnbind() {
+        mConnection.addCallback(mCallback);
+        mExecutor.runAll();
+        mConnection.bind();
+        mConnection.unbind();
+
+        // Ensure the callback doesn't get triggered until the executor runs.
+        verify(mCallback, never()).onDisconnected(eq(mConnection), anyInt());
+        mExecutor.runAll();
+        verify(mCallback).onDisconnected(mConnection,
+                ObservableServiceConnection.DISCONNECT_REASON_UNBIND);
+    }
+
+    static class FakeExecutor implements Executor {
+        private final Queue<Runnable> mQueue = new ArrayDeque<>();
+
+        @Override
+        public void execute(Runnable command) {
+            mQueue.add(command);
+        }
+
+        public void runAll() {
+            while (!mQueue.isEmpty()) {
+                mQueue.remove().run();
+            }
+        }
+
+        public void clearAll() {
+            while (!mQueue.isEmpty()) {
+                mQueue.remove();
+            }
+        }
+    }
+}
diff --git a/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java b/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java
new file mode 100644
index 0000000..fee4654
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/PersistentServiceConnectionTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+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.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.IBinder;
+
+import com.android.internal.util.ObservableServiceConnection.ServiceTransformer;
+import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+import java.util.concurrent.Executor;
+
+public class PersistentServiceConnectionTest {
+    private static final ComponentName COMPONENT_NAME =
+            new ComponentName("test.package", "component");
+    private static final int MAX_RETRIES = 2;
+    private static final int RETRY_DELAY_MS = 1000;
+    private static final int CONNECTION_MIN_DURATION_MS = 5000;
+    private PersistentServiceConnection<Proxy> mConnection;
+
+    public static class Proxy {
+    }
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private Intent mIntent;
+    @Mock
+    private Proxy mResult;
+    @Mock
+    private IBinder mBinder;
+    @Mock
+    private ServiceTransformer<Proxy> mTransformer;
+    @Mock
+    private ObservableServiceConnection.Callback<Proxy> mCallback;
+    private TestHandler mHandler;
+    private final FakeExecutor mFakeExecutor = new FakeExecutor();
+    private OffsettableClock mClock;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        mClock = new OffsettableClock.Stopped();
+        mHandler = spy(new TestHandler(null, mClock));
+
+        mConnection = new PersistentServiceConnection<>(
+                mContext,
+                mFakeExecutor,
+                mHandler,
+                mTransformer,
+                mIntent,
+                /* flags= */ Context.BIND_AUTO_CREATE,
+                CONNECTION_MIN_DURATION_MS,
+                MAX_RETRIES,
+                RETRY_DELAY_MS,
+                new TestInjector(mClock));
+
+        mClock.fastForward(1000);
+        mConnection.addCallback(mCallback);
+        when(mTransformer.convert(mBinder)).thenReturn(mResult);
+    }
+
+    @After
+    public void tearDown() {
+        mFakeExecutor.clearAll();
+    }
+
+    @Test
+    public void testConnect() {
+        mConnection.bind();
+        mConnection.onServiceConnected(COMPONENT_NAME, mBinder);
+        mFakeExecutor.runAll();
+        // Ensure that we did not schedule a retry
+        verify(mHandler, never()).postDelayed(any(), anyLong());
+    }
+
+    @Test
+    public void testRetryOnBindFailure() {
+        mConnection.bind();
+
+        verify(mContext, times(1)).bindService(
+                eq(mIntent),
+                anyInt(),
+                eq(mFakeExecutor),
+                eq(mConnection));
+
+        // After disconnect, a reconnection should be attempted after the RETRY_DELAY_MS
+        mConnection.onServiceDisconnected(COMPONENT_NAME);
+        mFakeExecutor.runAll();
+        advanceTime(RETRY_DELAY_MS);
+        verify(mContext, times(2)).bindService(
+                eq(mIntent),
+                anyInt(),
+                eq(mFakeExecutor),
+                eq(mConnection));
+
+        // Reconnect attempt #2
+        mConnection.onServiceDisconnected(COMPONENT_NAME);
+        mFakeExecutor.runAll();
+        advanceTime(RETRY_DELAY_MS * 2);
+        verify(mContext, times(3)).bindService(
+                eq(mIntent),
+                anyInt(),
+                eq(mFakeExecutor),
+                eq(mConnection));
+
+        // There should be no more reconnect attempts, since the maximum is 2
+        mConnection.onServiceDisconnected(COMPONENT_NAME);
+        mFakeExecutor.runAll();
+        advanceTime(RETRY_DELAY_MS * 4);
+        verify(mContext, times(3)).bindService(
+                eq(mIntent),
+                anyInt(),
+                eq(mFakeExecutor),
+                eq(mConnection));
+    }
+
+    @Test
+    public void testManualUnbindDoesNotReconnect() {
+        mConnection.bind();
+
+        verify(mContext, times(1)).bindService(
+                eq(mIntent),
+                anyInt(),
+                eq(mFakeExecutor),
+                eq(mConnection));
+
+        mConnection.unbind();
+        // Ensure that disconnection after unbind does not reconnect.
+        mConnection.onServiceDisconnected(COMPONENT_NAME);
+        mFakeExecutor.runAll();
+        advanceTime(RETRY_DELAY_MS);
+
+        verify(mContext, times(1)).bindService(
+                eq(mIntent),
+                anyInt(),
+                eq(mFakeExecutor),
+                eq(mConnection));
+    }
+
+    private void advanceTime(long millis) {
+        mClock.fastForward(millis);
+        mHandler.timeAdvance();
+    }
+
+    static class TestInjector extends PersistentServiceConnection.Injector {
+        private final OffsettableClock mClock;
+
+        TestInjector(OffsettableClock clock) {
+            mClock = clock;
+        }
+
+        @Override
+        public long uptimeMillis() {
+            return mClock.now();
+        }
+    }
+
+    static class FakeExecutor implements Executor {
+        private final Queue<Runnable> mQueue = new ArrayDeque<>();
+
+        @Override
+        public void execute(Runnable command) {
+            mQueue.add(command);
+        }
+
+        public void runAll() {
+            while (!mQueue.isEmpty()) {
+                mQueue.remove().run();
+            }
+        }
+
+        public void clearAll() {
+            while (!mQueue.isEmpty()) {
+                mQueue.remove();
+            }
+        }
+    }
+}
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 203ece0..1174b68 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -240,6 +240,16 @@
     }
 
     /**
+     * Clears the listener set in {@link SplitController#setSplitInfoListener}.
+     */
+    @Override
+    public void clearSplitInfoCallback() {
+        synchronized (mLock) {
+            mEmbeddingCallback = null;
+        }
+    }
+
+    /**
      * Called when the transaction is ready so that the organizer can update the TaskFragments based
      * on the changes in transaction.
      */
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 91573ff..00943f2d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -140,7 +140,7 @@
     void updateTaskFragmentParentInfo(@NonNull TaskFragmentParentInfo info) {
         mConfiguration.setTo(info.getConfiguration());
         mDisplayId = info.getDisplayId();
-        mIsVisible = info.isVisibleRequested();
+        mIsVisible = info.isVisible();
     }
 
     /**
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index c76f568..0fb6ff8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -103,14 +103,23 @@
     /**
      * Similar to {@link #addWindowLayoutInfoListener(Activity, Consumer)}, but takes a UI Context
      * as a parameter.
+     *
+     * Jetpack {@link androidx.window.layout.ExtensionWindowLayoutInfoBackend} makes sure all
+     * consumers related to the same {@link Context} gets updated {@link WindowLayoutInfo}
+     * together. However only the first registered consumer of a {@link Context} will actually
+     * invoke {@link #addWindowLayoutInfoListener(Context, Consumer)}.
+     * Here we enforce that {@link #addWindowLayoutInfoListener(Context, Consumer)} can only be
+     * called once for each {@link Context}.
      */
-    // TODO(b/204073440): Add @Override to hook the API in WM extensions library.
+    @Override
     public void addWindowLayoutInfoListener(@NonNull @UiContext Context context,
             @NonNull Consumer<WindowLayoutInfo> consumer) {
         if (mWindowLayoutChangeListeners.containsKey(context)
+                // In theory this method can be called on the same consumer with different context.
                 || mWindowLayoutChangeListeners.containsValue(consumer)) {
-            // Early return if the listener or consumer has been registered.
-            return;
+            throw new IllegalArgumentException(
+                    "Context or Consumer has already been registered for WindowLayoutInfo"
+                            + " callback.");
         }
         if (!context.isUiContext()) {
             throw new IllegalArgumentException("Context must be a UI Context, which should be"
diff --git a/libs/WindowManager/Jetpack/window-extensions-release.aar b/libs/WindowManager/Jetpack/window-extensions-release.aar
index 2c766d8..4978e04 100644
--- a/libs/WindowManager/Jetpack/window-extensions-release.aar
+++ b/libs/WindowManager/Jetpack/window-extensions-release.aar
Binary files differ
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 7960dec..f615ad6 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -44,6 +44,10 @@
     srcs: [
         "src/com/android/wm/shell/util/**/*.java",
         "src/com/android/wm/shell/common/split/SplitScreenConstants.java",
+        "src/com/android/wm/shell/sysui/ShellSharedConstants.java",
+        "src/com/android/wm/shell/common/TransactionPool.java",
+        "src/com/android/wm/shell/animation/Interpolators.java",
+        "src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java",
     ],
     path: "src",
 }
@@ -100,6 +104,21 @@
     out: ["wm_shell_protolog.json"],
 }
 
+genrule {
+    name: "protolog.json.gz",
+    srcs: [":generate-wm_shell_protolog.json"],
+    out: ["wmshell.protolog.json.gz"],
+    cmd: "$(location minigzip) -c < $(in) > $(out)",
+    tools: ["minigzip"],
+}
+
+prebuilt_etc {
+    name: "wmshell.protolog.json.gz",
+    system_ext_specific: true,
+    src: ":protolog.json.gz",
+    filename_from_src: true,
+}
+
 // End ProtoLog
 
 java_library {
@@ -123,9 +142,6 @@
     resource_dirs: [
         "res",
     ],
-    java_resources: [
-        ":generate-wm_shell_protolog.json",
-    ],
     static_libs: [
         "androidx.appcompat_appcompat",
         "androidx.arch.core_core-runtime",
diff --git a/libs/WindowManager/Shell/res/drawable/decor_back_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_back_button_dark.xml
new file mode 100644
index 0000000..66e5b43
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/decor_back_button_dark.xml
@@ -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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0"
+        >
+    <group android:scaleX="0.5"
+           android:scaleY="0.5"
+           android:translateX="8.0"
+           android:translateY="8.0" >
+        <path
+            android:fillColor="@android:color/black"
+            android:pathData="MM24,40.3 L7.7,24 24,7.7 26.8,10.45 15.3,22H40.3V26H15.3L26.8,37.5Z"/>
+
+    </group>
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/decor_caption_title.xml b/libs/WindowManager/Shell/res/drawable/decor_caption_title.xml
index 8207365..53a8bb1 100644
--- a/libs/WindowManager/Shell/res/drawable/decor_caption_title.xml
+++ b/libs/WindowManager/Shell/res/drawable/decor_caption_title.xml
@@ -15,8 +15,6 @@
   ~ limitations under the License.
   -->
 <shape android:shape="rectangle"
-       android:tintMode="multiply"
-       android:tint="@color/decor_caption_title_color"
        xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="?android:attr/colorPrimary" />
+    <solid android:color="@android:color/white" />
 </shape>
diff --git a/libs/WindowManager/Shell/res/drawable/decor_close_button_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_close_button_dark.xml
index f2f1a1d..851cbf2 100644
--- a/libs/WindowManager/Shell/res/drawable/decor_close_button_dark.xml
+++ b/libs/WindowManager/Shell/res/drawable/decor_close_button_dark.xml
@@ -18,15 +18,13 @@
         android:width="32.0dp"
         android:height="32.0dp"
         android:viewportWidth="32.0"
-        android:viewportHeight="32.0"
-        android:tint="@color/decor_button_dark_color"
-        >
+        android:viewportHeight="32.0">
     <group android:scaleX="0.5"
             android:scaleY="0.5"
             android:translateX="8.0"
             android:translateY="8.0" >
         <path
-            android:fillColor="@android:color/white"
-            android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
+            android:fillColor="@android:color/black"
+            android:pathData="M12.45,38.35 L9.65,35.55 21.2,24 9.65,12.45 12.45,9.65 24,21.2 35.55,9.65 38.35,12.45 26.8,24 38.35,35.55 35.55,38.35 24,26.8Z"/>
     </group>
 </vector>
diff --git a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
new file mode 100644
index 0000000..ee0f466
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
@@ -0,0 +1,23 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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">
+    <path
+        android:fillColor="@android:color/black" android:pathData="M3,5V3H21V5Z"/>
+</vector>
diff --git a/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml b/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
index d183e42..38cd570 100644
--- a/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
+++ b/libs/WindowManager/Shell/res/layout/caption_window_decoration.xml
@@ -17,39 +17,33 @@
 <com.android.wm.shell.windowdecor.WindowDecorLinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/caption"
-    android:layout_width="match_parent"
+    android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:gravity="end"
+    android:gravity="center_horizontal"
     android:background="@drawable/decor_caption_title">
     <Button
-        android:id="@+id/minimize_window"
-        android:visibility="gone"
+        android:id="@+id/back_button"
         android:layout_width="32dp"
         android:layout_height="32dp"
         android:layout_margin="5dp"
         android:padding="4dp"
-        android:layout_gravity="top|end"
-        android:contentDescription="@string/maximize_button_text"
-        android:background="@drawable/decor_minimize_button_dark"
-        android:duplicateParentState="true"/>
+        android:contentDescription="@string/back_button_text"
+        android:background="@drawable/decor_back_button_dark"
+    />
     <Button
-        android:id="@+id/maximize_window"
-        android:layout_width="32dp"
+        android:id="@+id/caption_handle"
+        android:layout_width="128dp"
         android:layout_height="32dp"
         android:layout_margin="5dp"
         android:padding="4dp"
-        android:layout_gravity="center_vertical|end"
-        android:contentDescription="@string/maximize_button_text"
-        android:background="@drawable/decor_maximize_button_dark"
-        android:duplicateParentState="true"/>
+        android:contentDescription="@string/handle_text"
+        android:background="@drawable/decor_handle_dark"/>
     <Button
         android:id="@+id/close_window"
         android:layout_width="32dp"
         android:layout_height="32dp"
         android:layout_margin="5dp"
         android:padding="4dp"
-        android:layout_gravity="center_vertical|end"
         android:contentDescription="@string/close_button_text"
-        android:background="@drawable/decor_close_button_dark"
-        android:duplicateParentState="true"/>
-</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
+        android:background="@drawable/decor_close_button_dark"/>
+</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index f790787..0aae6a5 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -23,13 +23,13 @@
     <string name="pip_phone_enter_split" msgid="7042877263880641911">"Accesează ecranul împărțit"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meniu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
-    <string name="pip_notification_message" msgid="8854051911700302620">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
+    <string name="pip_notification_message" msgid="8854051911700302620">"Dacă nu vrei ca <xliff:g id="NAME">%s</xliff:g> să folosească această funcție, atinge pentru a deschide setările și dezactiveaz-o."</string>
     <string name="pip_play" msgid="3496151081459417097">"Redă"</string>
     <string name="pip_pause" msgid="690688849510295232">"Întrerupe"</string>
-    <string name="pip_skip_to_next" msgid="8403429188794867653">"Treceți la următorul"</string>
-    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Treceți la cel anterior"</string>
-    <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionați"</string>
-    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stocați"</string>
+    <string name="pip_skip_to_next" msgid="8403429188794867653">"Treci la următorul"</string>
+    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Treci la cel anterior"</string>
+    <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionează"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stochează"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulează stocarea"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
@@ -47,9 +47,9 @@
     <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Partea de sus: 30%"</string>
     <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Partea de jos pe ecran complet"</string>
     <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Folosirea modului cu o mână"</string>
-    <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pentru a ieși, glisați în sus din partea de jos a ecranului sau atingeți oriunde deasupra ferestrei aplicației"</string>
+    <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pentru a ieși, glisează în sus din partea de jos a ecranului sau atinge oriunde deasupra ferestrei aplicației"</string>
     <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Activează modul cu o mână"</string>
-    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Părăsiți modul cu o mână"</string>
+    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Ieși din modul cu o mână"</string>
     <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Setări pentru baloanele <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Suplimentar"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Adaugă înapoi în stivă"</string>
@@ -61,27 +61,27 @@
     <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mută în dreapta jos"</string>
     <string name="bubbles_app_settings" msgid="3617224938701566416">"Setări <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Închide balonul"</string>
-    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișați conversația în balon"</string>
+    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișa conversația în balon"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat cu baloane"</string>
-    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
-    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlați oricând baloanele"</string>
-    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
+    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atinge pentru a deschide balonul. Trage pentru a-l muta."</string>
+    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlează oricând baloanele"</string>
+    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Atinge Gestionează pentru a dezactiva baloanele din această aplicație"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nu există baloane recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Baloanele recente și baloanele respinse vor apărea aici"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionează"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
-    <string name="restart_button_description" msgid="6712141648865547958">"Atingeți ca să reporniți aplicația pentru o vizualizare mai bună."</string>
-    <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="restart_button_description" msgid="6712141648865547958">"Atinge ca să repornești aplicația pentru o vizualizare mai bună."</string>
+    <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ai probleme cu camera foto?\nAtinge pentru a reîncadra"</string>
+    <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ai remediat problema?\nAtinge pentru a reveni"</string>
+    <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu ai probleme cu camera foto? Atinge pentru a închide."</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string>
     <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extinde pentru mai multe informații"</string>
-    <string name="maximize_button_text" msgid="1650859196290301963">"Maximizați"</string>
+    <string name="maximize_button_text" msgid="1650859196290301963">"Maximizează"</string>
     <string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string>
     <string name="close_button_text" msgid="2913281996024033299">"Închide"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
index 36df286..b5245ff 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings_tv.xml
@@ -26,8 +26,8 @@
     <string name="pip_collapse" msgid="3903295106641385962">"Restrânge"</string>
     <string name="pip_edu_text" msgid="3672999496647508701">" Apasă de două ori "<annotation icon="home_icon">"butonul ecran de pornire"</annotation>" pentru comenzi"</string>
     <string name="a11y_pip_menu_entered" msgid="5106343214776801614">"Meniu picture-in-picture."</string>
-    <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mută spre stânga"</string>
-    <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mută spre dreapta"</string>
+    <string name="a11y_action_pip_move_left" msgid="6612980937817141583">"Mută la stânga"</string>
+    <string name="a11y_action_pip_move_right" msgid="1119409122645529936">"Mută la dreapta"</string>
     <string name="a11y_action_pip_move_up" msgid="98502616918621959">"Mută în sus"</string>
     <string name="a11y_action_pip_move_down" msgid="3858802832725159740">"Mută în jos"</string>
     <string name="a11y_action_pip_move_done" msgid="1486845365134416210">"Gata"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 88bb130..a3e21f7 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -28,7 +28,7 @@
     <string name="pip_pause" msgid="690688849510295232">"పాజ్ చేయి"</string>
     <string name="pip_skip_to_next" msgid="8403429188794867653">"దాటవేసి తర్వాత దానికి వెళ్లు"</string>
     <string name="pip_skip_to_prev" msgid="7172158111196394092">"దాటవేసి మునుపటి దానికి వెళ్లు"</string>
-    <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"పరిమాణం మార్చు"</string>
+    <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"సైజ్‌ మార్చు"</string>
     <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index f03b7f6..30c3d50 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -19,6 +19,10 @@
          by the resources of the app using the Shell library. -->
     <bool name="config_enableShellMainThread">false</bool>
 
+    <!-- Determines whether to register the shell task organizer on init.
+         TODO(b/238217847): This config is temporary until we refactor the base WMComponent. -->
+    <bool name="config_registerShellTaskOrganizerOnInit">true</bool>
+
     <!-- Animation duration for PIP when entering. -->
     <integer name="config_pipEnterAnimationDuration">425</integer>
 
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index 1d1162d..d8a5074 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -193,4 +193,8 @@
      <string name="minimize_button_text">Minimize</string>
     <!-- Accessibility text for the close window button [CHAR LIMIT=NONE] -->
     <string name="close_button_text">Close</string>
+    <!-- Accessibility text for the caption back button [CHAR LIMIT=NONE] -->
+    <string name="back_button_text">Back</string>
+    <!-- Accessibility text for the caption handle [CHAR LIMIT=NONE] -->
+    <string name="handle_text">Handle</string>
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 1c0e6f7..756d802 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -20,6 +20,9 @@
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
 import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
 
+import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
+
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -42,7 +45,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
-import java.util.function.BiFunction;
 
 /** To run the ActivityEmbedding animations. */
 class ActivityEmbeddingAnimationRunner {
@@ -85,7 +87,7 @@
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Runnable animationFinishCallback) {
         final List<ActivityEmbeddingAnimationAdapter> adapters =
-                createAnimationAdapters(info, startTransaction);
+                createAnimationAdapters(info, startTransaction, finishTransaction);
         long duration = 0;
         for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
             duration = Math.max(duration, adapter.getDurationHint());
@@ -129,7 +131,8 @@
      */
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
-            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
         boolean isChangeTransition = false;
         for (TransitionInfo.Change change : info.getChanges()) {
             if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
@@ -145,23 +148,25 @@
             return createChangeAnimationAdapters(info, startTransaction);
         }
         if (Transitions.isClosingType(info.getType())) {
-            return createCloseAnimationAdapters(info);
+            return createCloseAnimationAdapters(info, startTransaction, finishTransaction);
         }
-        return createOpenAnimationAdapters(info);
+        return createOpenAnimationAdapters(info, startTransaction, finishTransaction);
     }
 
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
-            @NonNull TransitionInfo info) {
-        return createOpenCloseAnimationAdapters(info, true /* isOpening */,
-                mAnimationSpec::loadOpenAnimation);
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
+                true /* isOpening */, mAnimationSpec::loadOpenAnimation);
     }
 
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
-            @NonNull TransitionInfo info) {
-        return createOpenCloseAnimationAdapters(info, false /* isOpening */,
-                mAnimationSpec::loadCloseAnimation);
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
+                false /* isOpening */, mAnimationSpec::loadCloseAnimation);
     }
 
     /**
@@ -170,8 +175,9 @@
      */
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
-            @NonNull TransitionInfo info, boolean isOpening,
-            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider) {
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening,
+            @NonNull AnimationProvider animationProvider) {
         // We need to know if the change window is only a partial of the whole animation screen.
         // If so, we will need to adjust it to make the whole animation screen looks like one.
         final List<TransitionInfo.Change> openingChanges = new ArrayList<>();
@@ -194,7 +200,8 @@
         final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
         for (TransitionInfo.Change change : openingChanges) {
             final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
-                    change, animationProvider, openingWholeScreenBounds);
+                    info, change, startTransaction, finishTransaction, animationProvider,
+                    openingWholeScreenBounds);
             if (isOpening) {
                 adapter.overrideLayer(offsetLayer++);
             }
@@ -202,7 +209,8 @@
         }
         for (TransitionInfo.Change change : closingChanges) {
             final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
-                    change, animationProvider, closingWholeScreenBounds);
+                    info, change, startTransaction, finishTransaction, animationProvider,
+                    closingWholeScreenBounds);
             if (!isOpening) {
                 adapter.overrideLayer(offsetLayer++);
             }
@@ -213,10 +221,18 @@
 
     @NonNull
     private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter(
-            @NonNull TransitionInfo.Change change,
-            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
-            @NonNull Rect wholeAnimationBounds) {
-        final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
+            @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
+        final Animation animation = animationProvider.get(info, change, wholeAnimationBounds);
+        // We may want to show a background color for open/close transition.
+        final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation,
+                0 /* defaultColor */);
+        if (backgroundColor != 0) {
+            addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction,
+                    finishTransaction);
+        }
         return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
                 wholeAnimationBounds);
     }
@@ -322,4 +338,10 @@
         return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
                 animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
     }
+
+    /** To provide an {@link Animation} based on the transition infos. */
+    private interface AnimationProvider {
+        Animation get(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
+                @NonNull Rect animationBounds);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index ad0dddf..eb6ac76 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -17,6 +17,9 @@
 package com.android.wm.shell.activityembedding;
 
 
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
+
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -33,7 +36,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.R;
 import com.android.internal.policy.TransitionAnimation;
 import com.android.wm.shell.transition.Transitions;
 
@@ -175,16 +177,20 @@
     }
 
     @NonNull
-    Animation loadOpenAnimation(@NonNull TransitionInfo.Change change,
-            @NonNull Rect wholeAnimationBounds) {
+    Animation loadOpenAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
         final boolean isEnter = Transitions.isOpeningType(change.getMode());
         final Animation animation;
-        // TODO(b/207070762):
-        // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
-        // 2. Implement edgeExtension version
-        animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
-                ? R.anim.task_fragment_open_enter
-                : R.anim.task_fragment_open_exit);
+        // TODO(b/207070762): Implement edgeExtension version
+        if (shouldShowBackdrop(info, change)) {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_clear_top_open_enter
+                    : com.android.internal.R.anim.task_fragment_clear_top_open_exit);
+        } else {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_open_enter
+                    : com.android.internal.R.anim.task_fragment_open_exit);
+        }
         // Use the whole animation bounds instead of the change bounds, so that when multiple change
         // targets are opening at the same time, the animation applied to each will be the same.
         // Otherwise, we may see gap between the activities that are launching together.
@@ -195,16 +201,20 @@
     }
 
     @NonNull
-    Animation loadCloseAnimation(@NonNull TransitionInfo.Change change,
-            @NonNull Rect wholeAnimationBounds) {
+    Animation loadCloseAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
         final boolean isEnter = Transitions.isOpeningType(change.getMode());
         final Animation animation;
-        // TODO(b/207070762):
-        // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
-        // 2. Implement edgeExtension version
-        animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
-                ? R.anim.task_fragment_close_enter
-                : R.anim.task_fragment_close_exit);
+        // TODO(b/207070762): Implement edgeExtension version
+        if (shouldShowBackdrop(info, change)) {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_clear_top_close_enter
+                    : com.android.internal.R.anim.task_fragment_clear_top_close_exit);
+        } else {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_close_enter
+                    : com.android.internal.R.anim.task_fragment_close_exit);
+        }
         // Use the whole animation bounds instead of the change bounds, so that when multiple change
         // targets are closing at the same time, the animation applied to each will be the same.
         // Otherwise, we may see gap between the activities that are finishing together.
@@ -213,4 +223,11 @@
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         return animation;
     }
+
+    private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change) {
+        final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
+                mTransitionAnimation);
+        return a != null && a.getShowBackdrop();
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
index 86f9d5b..8cbe44b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimation.java
@@ -29,13 +29,6 @@
 public interface BackAnimation {
 
     /**
-     * Returns a binder that can be passed to an external process to update back animations.
-     */
-    default IBackAnimation createExternalInterface() {
-        return null;
-    }
-
-    /**
      * Called when a {@link MotionEvent} is generated by a back gesture.
      *
      * @param touchX the X touch position of the {@link MotionEvent}.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 33ecdd8..938189f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -21,6 +21,7 @@
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -57,10 +58,12 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.annotations.ShellBackgroundThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -105,6 +108,7 @@
     private final IActivityTaskManager mActivityTaskManager;
     private final Context mContext;
     private final ContentResolver mContentResolver;
+    private final ShellController mShellController;
     private final ShellExecutor mShellExecutor;
     private final Handler mBgHandler;
     @Nullable
@@ -231,21 +235,25 @@
 
     public BackAnimationController(
             @NonNull ShellInit shellInit,
+            @NonNull ShellController shellController,
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler backgroundHandler,
             Context context) {
-        this(shellInit, shellExecutor, backgroundHandler, new SurfaceControl.Transaction(),
-                ActivityTaskManager.getService(), context, context.getContentResolver());
+        this(shellInit, shellController, shellExecutor, backgroundHandler,
+                new SurfaceControl.Transaction(), ActivityTaskManager.getService(),
+                context, context.getContentResolver());
     }
 
     @VisibleForTesting
     BackAnimationController(
             @NonNull ShellInit shellInit,
+            @NonNull ShellController shellController,
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler bgHandler,
             @NonNull SurfaceControl.Transaction transaction,
             @NonNull IActivityTaskManager activityTaskManager,
             Context context, ContentResolver contentResolver) {
+        mShellController = shellController;
         mShellExecutor = shellExecutor;
         mTransaction = transaction;
         mActivityTaskManager = activityTaskManager;
@@ -257,6 +265,8 @@
 
     private void onInit() {
         setupAnimationDeveloperSettingsObserver(mContentResolver, mBgHandler);
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_BACK_ANIMATION,
+                this::createExternalInterface, this);
     }
 
     private void setupAnimationDeveloperSettingsObserver(
@@ -289,7 +299,11 @@
         return mBackAnimation;
     }
 
-    private final BackAnimation mBackAnimation = new BackAnimationImpl();
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IBackAnimationImpl(this);
+    }
+
+    private final BackAnimationImpl mBackAnimation = new BackAnimationImpl();
 
     @Override
     public Context getContext() {
@@ -302,17 +316,6 @@
     }
 
     private class BackAnimationImpl implements BackAnimation {
-        private IBackAnimationImpl mBackAnimation;
-
-        @Override
-        public IBackAnimation createExternalInterface() {
-            if (mBackAnimation != null) {
-                mBackAnimation.invalidate();
-            }
-            mBackAnimation = new IBackAnimationImpl(BackAnimationController.this);
-            return mBackAnimation;
-        }
-
         @Override
         public void onBackMotion(
                 float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge) {
@@ -331,7 +334,8 @@
         }
     }
 
-    private static class IBackAnimationImpl extends IBackAnimation.Stub {
+    private static class IBackAnimationImpl extends IBackAnimation.Stub
+            implements ExternalInterfaceBinder {
         private BackAnimationController mController;
 
         IBackAnimationImpl(BackAnimationController controller) {
@@ -356,7 +360,8 @@
                     (controller) -> controller.onBackToLauncherAnimationFinished());
         }
 
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DockStateReader.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DockStateReader.java
new file mode 100644
index 0000000..e029358
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DockStateReader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.common;
+
+import static android.content.Intent.EXTRA_DOCK_STATE;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import com.android.wm.shell.dagger.WMSingleton;
+
+import javax.inject.Inject;
+
+/**
+ * Provides information about the docked state of the device.
+ */
+@WMSingleton
+public class DockStateReader {
+
+    private static final IntentFilter DOCK_INTENT_FILTER = new IntentFilter(
+            Intent.ACTION_DOCK_EVENT);
+
+    private final Context mContext;
+
+    @Inject
+    public DockStateReader(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * @return True if the device is docked and false otherwise.
+     */
+    public boolean isDocked() {
+        Intent dockStatus = mContext.registerReceiver(/* receiver */ null, DOCK_INTENT_FILTER);
+        if (dockStatus != null) {
+            int dockState = dockStatus.getIntExtra(EXTRA_DOCK_STATE,
+                    Intent.EXTRA_DOCK_STATE_UNDOCKED);
+            return dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java
index 44c0496..aa5b0cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java
@@ -14,14 +14,21 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.wm.shell.common;
+
+import android.os.IBinder;
 
 /**
- * Provides information on the current wifi activity.
+ * An interface for binders which can be registered to be sent to other processes.
  */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+public interface ExternalInterfaceBinder {
+    /**
+     * Invalidates this binder (detaches it from the controller it would call).
+     */
+    void invalidate();
+
+    /**
+     * Returns the IBinder to send.
+     */
+    IBinder asBinder();
+}
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 419e62d..c2ad1a9 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
@@ -118,6 +118,7 @@
     private boolean mFreezeDividerWindow = false;
     private int mOrientation;
     private int mRotation;
+    private int mDensity;
 
     private final boolean mDimNonImeSide;
 
@@ -290,9 +291,11 @@
         final int rotation = configuration.windowConfiguration.getRotation();
         final Rect rootBounds = configuration.windowConfiguration.getBounds();
         final int orientation = configuration.orientation;
+        final int density = configuration.densityDpi;
 
         if (mOrientation == orientation
                 && mRotation == rotation
+                && mDensity == density
                 && mRootBounds.equals(rootBounds)) {
             return false;
         }
@@ -303,6 +306,7 @@
         mTempRect.set(mRootBounds);
         mRootBounds.set(rootBounds);
         mRotation = rotation;
+        mDensity = density;
         mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds, null);
         initDividerPosition(mTempRect);
         updateInvisibleRect();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 235fd9c..6627de5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -37,6 +37,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.CompatUIWindowManager.CompatUIHintsState;
@@ -109,6 +110,7 @@
     private final SyncTransactionQueue mSyncQueue;
     private final ShellExecutor mMainExecutor;
     private final Lazy<Transitions> mTransitionsLazy;
+    private final DockStateReader mDockStateReader;
 
     private CompatUICallback mCallback;
 
@@ -127,7 +129,8 @@
             DisplayImeController imeController,
             SyncTransactionQueue syncQueue,
             ShellExecutor mainExecutor,
-            Lazy<Transitions> transitionsLazy) {
+            Lazy<Transitions> transitionsLazy,
+            DockStateReader dockStateReader) {
         mContext = context;
         mShellController = shellController;
         mDisplayController = displayController;
@@ -138,6 +141,7 @@
         mTransitionsLazy = transitionsLazy;
         mCompatUIHintsState = new CompatUIHintsState();
         shellInit.addInitCallback(this::onInit, this);
+        mDockStateReader = dockStateReader;
     }
 
     private void onInit() {
@@ -315,7 +319,8 @@
         return new LetterboxEduWindowManager(context, taskInfo,
                 mSyncQueue, taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
                 mTransitionsLazy.get(),
-                this::onLetterboxEduDismissed);
+                this::onLetterboxEduDismissed,
+                mDockStateReader);
     }
 
     private void onLetterboxEduDismissed() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
index 35f1038..867d0ef 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java
@@ -34,6 +34,7 @@
 import com.android.wm.shell.R;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.CompatUIWindowManagerAbstract;
 import com.android.wm.shell.transition.Transitions;
@@ -88,19 +89,21 @@
      */
     private final int mDialogVerticalMargin;
 
+    private final DockStateReader mDockStateReader;
+
     public LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
             SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
             DisplayLayout displayLayout, Transitions transitions,
-            Runnable onDismissCallback) {
+            Runnable onDismissCallback, DockStateReader dockStateReader) {
         this(context, taskInfo, syncQueue, taskListener, displayLayout, transitions,
-                onDismissCallback, new LetterboxEduAnimationController(context));
+                onDismissCallback, new LetterboxEduAnimationController(context), dockStateReader);
     }
 
     @VisibleForTesting
     LetterboxEduWindowManager(Context context, TaskInfo taskInfo,
             SyncTransactionQueue syncQueue, ShellTaskOrganizer.TaskListener taskListener,
             DisplayLayout displayLayout, Transitions transitions, Runnable onDismissCallback,
-            LetterboxEduAnimationController animationController) {
+            LetterboxEduAnimationController animationController, DockStateReader dockStateReader) {
         super(context, taskInfo, syncQueue, taskListener, displayLayout);
         mTransitions = transitions;
         mOnDismissCallback = onDismissCallback;
@@ -111,6 +114,7 @@
                 Context.MODE_PRIVATE);
         mDialogVerticalMargin = (int) mContext.getResources().getDimension(
                 R.dimen.letterbox_education_dialog_margin);
+        mDockStateReader = dockStateReader;
     }
 
     @Override
@@ -130,13 +134,15 @@
 
     @Override
     protected boolean eligibleToShowLayout() {
+        // - The letterbox education should not be visible if the device is docked.
         // - If taskbar education is showing, the letterbox education shouldn't be shown for the
         //   given task until the taskbar education is dismissed and the compat info changes (then
         //   the controller will create a new instance of this class since this one isn't eligible).
         // - If the layout isn't null then it was previously showing, and we shouldn't check if the
         //   user has seen the letterbox education before.
-        return mEligibleForLetterboxEducation && !isTaskbarEduShowing() && (mLayout != null
-                || !getHasSeenLetterboxEducation());
+        return mEligibleForLetterboxEducation && !isTaskbarEduShowing()
+                && (mLayout != null || !getHasSeenLetterboxEducation())
+                && !mDockStateReader.isDocked();
     }
 
     @Override
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 33074de..28a1959 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
@@ -29,6 +29,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.ProtoLogController;
+import com.android.wm.shell.R;
 import com.android.wm.shell.RootDisplayAreaOrganizer;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -45,6 +46,7 @@
 import com.android.wm.shell.common.DisplayImeController;
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.FloatingContentCoordinator;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -57,6 +59,8 @@
 import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
 import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.desktopmode.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeController;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
@@ -66,7 +70,6 @@
 import com.android.wm.shell.freeform.FreeformComponents;
 import com.android.wm.shell.fullscreen.FullscreenTaskListener;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutoutController;
-import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
 import com.android.wm.shell.onehanded.OneHanded;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.Pip;
@@ -171,6 +174,7 @@
     @WMSingleton
     @Provides
     static ShellTaskOrganizer provideShellTaskOrganizer(
+            Context context,
             ShellInit shellInit,
             ShellCommandHandler shellCommandHandler,
             CompatUIController compatUI,
@@ -178,39 +182,26 @@
             Optional<RecentTasksController> recentTasksOptional,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
+        if (!context.getResources().getBoolean(R.bool.config_registerShellTaskOrganizerOnInit)) {
+            // TODO(b/238217847): Force override shell init if registration is disabled
+            shellInit = new ShellInit(mainExecutor);
+        }
         return new ShellTaskOrganizer(shellInit, shellCommandHandler, compatUI,
                 unfoldAnimationController, recentTasksOptional, mainExecutor);
     }
 
     @WMSingleton
     @Provides
-    static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
-            Context context,
-            ShellInit shellInit,
-            ShellCommandHandler shellCommandHandler,
-            SyncTransactionQueue syncTransactionQueue,
-            DisplayController displayController,
-            DisplayInsetsController displayInsetsController,
-            Optional<UnfoldAnimationController> unfoldAnimationController,
-            Optional<RecentTasksController> recentTasksOptional,
-            @ShellMainThread ShellExecutor mainExecutor,
-            @ShellMainThread Handler mainHandler
-    ) {
-        return new KidsModeTaskOrganizer(context, shellInit, shellCommandHandler,
-                syncTransactionQueue, displayController, displayInsetsController,
-                unfoldAnimationController, recentTasksOptional, mainExecutor, mainHandler);
-    }
-
-    @WMSingleton
-    @Provides
     static CompatUIController provideCompatUIController(Context context,
             ShellInit shellInit,
             ShellController shellController,
             DisplayController displayController, DisplayInsetsController displayInsetsController,
             DisplayImeController imeController, SyncTransactionQueue syncQueue,
-            @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy) {
+            @ShellMainThread ShellExecutor mainExecutor, Lazy<Transitions> transitionsLazy,
+            DockStateReader dockStateReader) {
         return new CompatUIController(context, shellInit, shellController, displayController,
-                displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy);
+                displayInsetsController, imeController, syncQueue, mainExecutor, transitionsLazy,
+                dockStateReader);
     }
 
     @WMSingleton
@@ -270,13 +261,14 @@
     static Optional<BackAnimationController> provideBackAnimationController(
             Context context,
             ShellInit shellInit,
+            ShellController shellController,
             @ShellMainThread ShellExecutor shellExecutor,
             @ShellBackgroundThread Handler backgroundHandler
     ) {
         if (BackAnimationController.IS_ENABLED) {
             return Optional.of(
-                    new BackAnimationController(shellInit, shellExecutor, backgroundHandler,
-                            context));
+                    new BackAnimationController(shellInit, shellController, shellExecutor,
+                            backgroundHandler, context));
         }
         return Optional.empty();
     }
@@ -301,17 +293,17 @@
     // Workaround for dynamic overriding with a default implementation, see {@link DynamicOverride}
     @BindsOptionalOf
     @DynamicOverride
-    abstract FullscreenTaskListener<?> optionalFullscreenTaskListener();
+    abstract FullscreenTaskListener optionalFullscreenTaskListener();
 
     @WMSingleton
     @Provides
-    static FullscreenTaskListener<?> provideFullscreenTaskListener(
-            @DynamicOverride Optional<FullscreenTaskListener<?>> fullscreenTaskListener,
+    static FullscreenTaskListener provideFullscreenTaskListener(
+            @DynamicOverride Optional<FullscreenTaskListener> fullscreenTaskListener,
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue,
             Optional<RecentTasksController> recentTasksOptional,
-            Optional<WindowDecorViewModel<?>> windowDecorViewModelOptional) {
+            Optional<WindowDecorViewModel> windowDecorViewModelOptional) {
         if (fullscreenTaskListener.isPresent()) {
             return fullscreenTaskListener.get();
         } else {
@@ -325,7 +317,7 @@
     //
 
     @BindsOptionalOf
-    abstract WindowDecorViewModel<?> optionalWindowDecorViewModel();
+    abstract WindowDecorViewModel optionalWindowDecorViewModel();
 
     //
     // Unfold transition
@@ -480,14 +472,17 @@
     static Optional<RecentTasksController> provideRecentTasksController(
             Context context,
             ShellInit shellInit,
+            ShellController shellController,
             ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
+            ActivityTaskManager activityTaskManager,
             Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         return Optional.ofNullable(
-                RecentTasksController.create(context, shellInit, shellCommandHandler,
-                        taskStackListener, desktopModeTaskRepository, mainExecutor));
+                RecentTasksController.create(context, shellInit, shellController,
+                        shellCommandHandler, taskStackListener, activityTaskManager,
+                        desktopModeTaskRepository, mainExecutor));
     }
 
     //
@@ -504,14 +499,15 @@
     @Provides
     static Transitions provideTransitions(Context context,
             ShellInit shellInit,
+            ShellController shellController,
             ShellTaskOrganizer organizer,
             TransactionPool pool,
             DisplayController displayController,
             @ShellMainThread ShellExecutor mainExecutor,
             @ShellMainThread Handler mainHandler,
             @ShellAnimationThread ShellExecutor animExecutor) {
-        return new Transitions(context, shellInit, organizer, pool, displayController, mainExecutor,
-                mainHandler, animExecutor);
+        return new Transitions(context, shellInit, shellController, organizer, pool,
+                displayController, mainExecutor, mainHandler, animExecutor);
     }
 
     @WMSingleton
@@ -628,13 +624,15 @@
 
     @WMSingleton
     @Provides
-    static StartingWindowController provideStartingWindowController(Context context,
+    static StartingWindowController provideStartingWindowController(
+            Context context,
             ShellInit shellInit,
+            ShellController shellController,
             ShellTaskOrganizer shellTaskOrganizer,
             @ShellSplashscreenThread ShellExecutor splashScreenExecutor,
             StartingWindowTypeAlgorithm startingWindowTypeAlgorithm, IconProvider iconProvider,
             TransactionPool pool) {
-        return new StartingWindowController(context, shellInit, shellTaskOrganizer,
+        return new StartingWindowController(context, shellInit, shellController, shellTaskOrganizer,
                 splashScreenExecutor, startingWindowTypeAlgorithm, iconProvider, pool);
     }
 
@@ -716,15 +714,36 @@
     // Desktop mode (optional feature)
     //
 
+    @WMSingleton
+    @Provides
+    static Optional<DesktopMode> provideDesktopMode(
+            Optional<DesktopModeController> desktopModeController) {
+        return desktopModeController.map(DesktopModeController::asDesktopMode);
+    }
+
+    @BindsOptionalOf
+    @DynamicOverride
+    abstract DesktopModeController optionalDesktopModeController();
+
+    @WMSingleton
+    @Provides
+    static Optional<DesktopModeController> providesDesktopModeController(
+            @DynamicOverride Optional<DesktopModeController> desktopModeController) {
+        if (DesktopModeStatus.IS_SUPPORTED) {
+            return desktopModeController;
+        }
+        return Optional.empty();
+    }
+
     @BindsOptionalOf
     @DynamicOverride
     abstract DesktopModeTaskRepository optionalDesktopModeTaskRepository();
 
     @WMSingleton
     @Provides
-    static Optional<DesktopModeTaskRepository> providesDesktopModeTaskRepository(
+    static Optional<DesktopModeTaskRepository> providesDesktopTaskRepository(
             @DynamicOverride Optional<DesktopModeTaskRepository> desktopModeTaskRepository) {
-        if (DesktopMode.IS_SUPPORTED) {
+        if (DesktopModeStatus.IS_SUPPORTED) {
             return desktopModeTaskRepository;
         }
         return Optional.empty();
@@ -750,12 +769,11 @@
             DisplayInsetsController displayInsetsController,
             DragAndDropController dragAndDropController,
             ShellTaskOrganizer shellTaskOrganizer,
-            KidsModeTaskOrganizer kidsModeTaskOrganizer,
             Optional<BubbleController> bubblesOptional,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<Pip> pipOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
-            FullscreenTaskListener<?> fullscreenTaskListener,
+            FullscreenTaskListener fullscreenTaskListener,
             Optional<UnfoldAnimationController> unfoldAnimationController,
             Optional<UnfoldTransitionHandler> unfoldTransitionHandler,
             Optional<FreeformComponents> freeformComponents,
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 35e88e9..f1670cd 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
@@ -48,7 +48,6 @@
 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.DesktopMode;
 import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.draganddrop.DragAndDropController;
@@ -56,7 +55,7 @@
 import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.freeform.FreeformTaskTransitionHandler;
 import com.android.wm.shell.freeform.FreeformTaskTransitionObserver;
-import com.android.wm.shell.fullscreen.FullscreenTaskListener;
+import com.android.wm.shell.kidsmode.KidsModeTaskOrganizer;
 import com.android.wm.shell.onehanded.OneHandedController;
 import com.android.wm.shell.pip.Pip;
 import com.android.wm.shell.pip.PipAnimationController;
@@ -183,20 +182,22 @@
 
     @WMSingleton
     @Provides
-    static WindowDecorViewModel<?> provideWindowDecorViewModel(
+    static WindowDecorViewModel provideWindowDecorViewModel(
             Context context,
             @ShellMainThread Handler mainHandler,
             @ShellMainThread Choreographer mainChoreographer,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue,
+            @DynamicOverride DesktopModeController desktopModeController) {
         return new CaptionWindowDecorViewModel(
-                        context,
-                        mainHandler,
-                        mainChoreographer,
-                        taskOrganizer,
-                        displayController,
-                        syncQueue);
+                    context,
+                    mainHandler,
+                    mainChoreographer,
+                    taskOrganizer,
+                    displayController,
+                    syncQueue,
+                    desktopModeController);
     }
 
     //
@@ -207,7 +208,7 @@
     @Provides
     @DynamicOverride
     static FreeformComponents provideFreeformComponents(
-            FreeformTaskListener<?> taskListener,
+            FreeformTaskListener taskListener,
             FreeformTaskTransitionHandler transitionHandler,
             FreeformTaskTransitionObserver transitionObserver) {
         return new FreeformComponents(
@@ -216,18 +217,18 @@
 
     @WMSingleton
     @Provides
-    static FreeformTaskListener<?> provideFreeformTaskListener(
+    static FreeformTaskListener provideFreeformTaskListener(
             Context context,
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
-            WindowDecorViewModel<?> windowDecorViewModel) {
+            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, desktopModeTaskRepository,
+        return new FreeformTaskListener(init, shellTaskOrganizer, desktopModeTaskRepository,
                 windowDecorViewModel);
     }
 
@@ -236,7 +237,7 @@
     static FreeformTaskTransitionHandler provideFreeformTaskTransitionHandler(
             ShellInit shellInit,
             Transitions transitions,
-            WindowDecorViewModel<?> windowDecorViewModel) {
+            WindowDecorViewModel windowDecorViewModel) {
         return new FreeformTaskTransitionHandler(shellInit, transitions, windowDecorViewModel);
     }
 
@@ -246,10 +247,9 @@
             Context context,
             ShellInit shellInit,
             Transitions transitions,
-            FullscreenTaskListener<?> fullscreenTaskListener,
-            FreeformTaskListener<?> freeformTaskListener) {
+            WindowDecorViewModel windowDecorViewModel) {
         return new FreeformTaskTransitionObserver(
-                context, shellInit, transitions, fullscreenTaskListener, freeformTaskListener);
+                context, shellInit, transitions, windowDecorViewModel);
     }
 
     //
@@ -319,6 +319,7 @@
             ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
+            PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
@@ -338,11 +339,12 @@
             @ShellMainThread ShellExecutor mainExecutor) {
         return Optional.ofNullable(PipController.create(
                 context, shellInit, shellCommandHandler, shellController,
-                displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm,
-                pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
-                pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
-                windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                displayInsetsController, oneHandedController, mainExecutor));
+                displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm,
+                pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
+                phonePipMenuController, pipTaskOrganizer, pipTransitionState, pipTouchHandler,
+                pipTransitionController, windowManagerShellWrapper, taskStackListener,
+                pipParamsChangedForwarder, displayInsetsController, oneHandedController,
+                mainExecutor));
     }
 
     @WMSingleton
@@ -595,19 +597,20 @@
 
     @WMSingleton
     @Provides
-    static Optional<DesktopModeController> provideDesktopModeController(
-            Context context, ShellInit shellInit,
+    @DynamicOverride
+    static DesktopModeController provideDesktopModeController(Context context,
+            ShellInit shellInit,
+            ShellController shellController,
             ShellTaskOrganizer shellTaskOrganizer,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            Transitions transitions,
+            @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
             @ShellMainThread Handler mainHandler,
-            Transitions transitions
+            @ShellMainThread ShellExecutor mainExecutor
     ) {
-        if (DesktopMode.IS_SUPPORTED) {
-            return Optional.of(new DesktopModeController(context, shellInit, shellTaskOrganizer,
-                    rootTaskDisplayAreaOrganizer, mainHandler, transitions));
-        } else {
-            return Optional.empty();
-        }
+        return new DesktopModeController(context, shellInit, shellController, shellTaskOrganizer,
+                rootTaskDisplayAreaOrganizer, transitions, desktopModeTaskRepository, mainHandler,
+                mainExecutor);
     }
 
     @WMSingleton
@@ -618,6 +621,28 @@
     }
 
     //
+    // Kids mode
+    //
+    @WMSingleton
+    @Provides
+    static KidsModeTaskOrganizer provideKidsModeTaskOrganizer(
+            Context context,
+            ShellInit shellInit,
+            ShellCommandHandler shellCommandHandler,
+            SyncTransactionQueue syncTransactionQueue,
+            DisplayController displayController,
+            DisplayInsetsController displayInsetsController,
+            Optional<UnfoldAnimationController> unfoldAnimationController,
+            Optional<RecentTasksController> recentTasksOptional,
+            @ShellMainThread ShellExecutor mainExecutor,
+            @ShellMainThread Handler mainHandler
+    ) {
+        return new KidsModeTaskOrganizer(context, shellInit, shellCommandHandler,
+                syncTransactionQueue, displayController, displayInsetsController,
+                unfoldAnimationController, recentTasksOptional, mainExecutor, mainHandler);
+    }
+
+    //
     // Misc
     //
 
@@ -628,6 +653,7 @@
     @Provides
     static Object provideIndependentShellComponentsToCreate(
             DefaultMixedHandler defaultMixedHandler,
+            KidsModeTaskOrganizer kidsModeTaskOrganizer,
             Optional<DesktopModeController> desktopModeController) {
         return new Object();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index 8993d54..44a467f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -16,43 +16,11 @@
 
 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;
+import com.android.wm.shell.common.annotations.ExternalThread;
 
 /**
- * Constants for desktop mode feature
+ * Interface to interact with desktop mode feature in shell.
  */
-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;
-        }
-    }
+@ExternalThread
+public interface DesktopMode {
 }
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 6e44d58..b96facf 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
@@ -19,59 +19,117 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.view.WindowManager.TRANSIT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OPEN;
 
+import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
 
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.WindowConfiguration;
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.ArraySet;
+import android.view.SurfaceControl;
 import android.window.DisplayAreaInfo;
+import android.window.TransitionInfo;
+import android.window.TransitionRequestInfo;
 import android.window.WindowContainerTransaction;
 
+import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
+import com.android.wm.shell.common.RemoteCallable;
+import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
+import java.util.ArrayList;
+import java.util.Comparator;
+
 /**
  * Handles windowing changes when desktop mode system setting changes
  */
-public class DesktopModeController {
+public class DesktopModeController implements RemoteCallable<DesktopModeController>,
+        Transitions.TransitionHandler {
 
     private final Context mContext;
+    private final ShellController mShellController;
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
-    private final SettingsObserver mSettingsObserver;
     private final Transitions mTransitions;
+    private final DesktopModeTaskRepository mDesktopModeTaskRepository;
+    private final ShellExecutor mMainExecutor;
+    private final DesktopModeImpl mDesktopModeImpl = new DesktopModeImpl();
+    private final SettingsObserver mSettingsObserver;
 
-    public DesktopModeController(Context context, ShellInit shellInit,
+    public DesktopModeController(Context context,
+            ShellInit shellInit,
+            ShellController shellController,
             ShellTaskOrganizer shellTaskOrganizer,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
+            Transitions transitions,
+            DesktopModeTaskRepository desktopModeTaskRepository,
             @ShellMainThread Handler mainHandler,
-            Transitions transitions) {
+            @ShellMainThread ShellExecutor mainExecutor) {
         mContext = context;
+        mShellController = shellController;
         mShellTaskOrganizer = shellTaskOrganizer;
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
-        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
         mTransitions = transitions;
+        mDesktopModeTaskRepository = desktopModeTaskRepository;
+        mMainExecutor = mainExecutor;
+        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
         shellInit.addInitCallback(this::onInit, this);
     }
 
     private void onInit() {
         ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_DESKTOP_MODE,
+                this::createExternalInterface, this);
         mSettingsObserver.observe();
-        if (DesktopMode.isActive(mContext)) {
+        if (DesktopModeStatus.isActive(mContext)) {
             updateDesktopModeActive(true);
         }
+        mTransitions.addHandler(this);
+    }
+
+    @Override
+    public Context getContext() {
+        return mContext;
+    }
+
+    @Override
+    public ShellExecutor getRemoteCallExecutor() {
+        return mMainExecutor;
+    }
+
+    /**
+     * Get connection interface between sysui and shell
+     */
+    public DesktopMode asDesktopMode() {
+        return mDesktopModeImpl;
+    }
+
+    /**
+     * Creates a new instance of the external interface to pass to another process.
+     */
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IDesktopModeImpl(this);
     }
 
     @VisibleForTesting
@@ -121,6 +179,81 @@
     }
 
     /**
+     * Show apps on desktop
+     */
+    WindowContainerTransaction showDesktopApps() {
+        ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks();
+        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());
+        ArrayList<RunningTaskInfo> taskInfos = new ArrayList<>();
+        for (Integer taskId : activeTasks) {
+            RunningTaskInfo taskInfo = mShellTaskOrganizer.getRunningTaskInfo(taskId);
+            if (taskInfo != null) {
+                taskInfos.add(taskInfo);
+            }
+        }
+        // Order by lastActiveTime, descending
+        taskInfos.sort(Comparator.comparingLong(task -> -task.lastActiveTime));
+        WindowContainerTransaction wct = new WindowContainerTransaction();
+        for (RunningTaskInfo task : taskInfos) {
+            wct.reorder(task.token, true);
+        }
+
+        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
+            mShellTaskOrganizer.applyTransaction(wct);
+        }
+
+        return wct;
+    }
+
+    /**
+     * Turn desktop mode on or off
+     * @param active the desired state for desktop mode setting
+     */
+    public void setDesktopModeActive(boolean active) {
+        int value = active ? 1 : 0;
+        Settings.System.putInt(mContext.getContentResolver(), Settings.System.DESKTOP_MODE, value);
+    }
+
+    /**
+     * Returns the windowing mode of the display area with the specified displayId.
+     * @param displayId
+     * @return
+     */
+    public int getDisplayAreaWindowingMode(int displayId) {
+        return mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
+                .configuration.windowConfiguration.getWindowingMode();
+    }
+
+    @Override
+    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull Transitions.TransitionFinishCallback finishCallback) {
+        // This handler should never be the sole handler, so should not animate anything.
+        return false;
+    }
+
+    @Nullable
+    @Override
+    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+            @NonNull TransitionRequestInfo request) {
+
+        // Only do anything if we are in desktop mode and opening a task/app
+        if (!DesktopModeStatus.isActive(mContext) || request.getType() != TRANSIT_OPEN) {
+            return null;
+        }
+
+        WindowContainerTransaction wct = mTransitions.dispatchRequest(transition, request, this);
+        if (wct == null) {
+            wct = new WindowContainerTransaction();
+        }
+        wct.merge(showDesktopApps(), true /* transfer */);
+        wct.reorder(request.getTriggerTask().token, true /* onTop */);
+
+        return wct;
+    }
+
+    /**
      * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
      */
     private final class SettingsObserver extends ContentObserver {
@@ -150,8 +283,43 @@
         }
 
         private void desktopModeSettingChanged() {
-            boolean enabled = DesktopMode.isActive(mContext);
+            boolean enabled = DesktopModeStatus.isActive(mContext);
             updateDesktopModeActive(enabled);
         }
     }
+
+    /**
+     * The interface for calls from outside the shell, within the host process.
+     */
+    @ExternalThread
+    private final class DesktopModeImpl implements DesktopMode {
+        // Do nothing
+    }
+
+    /**
+     * The interface for calls from outside the host process.
+     */
+    @BinderThread
+    private static class IDesktopModeImpl extends IDesktopMode.Stub
+            implements ExternalInterfaceBinder {
+
+        private DesktopModeController mController;
+
+        IDesktopModeImpl(DesktopModeController controller) {
+            mController = controller;
+        }
+
+        /**
+         * Invalidates this instance, preventing future calls from updating the controller.
+         */
+        @Override
+        public void invalidate() {
+            mController = null;
+        }
+
+        public void showDesktopApps() {
+            executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
+                    DesktopModeController::showDesktopApps);
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
new file mode 100644
index 0000000..195ff50
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.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 DesktopModeStatus {
+
+    /**
+     * 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/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
similarity index 65%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
index 44c0496..5042bd6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/IDesktopMode.aidl
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.wm.shell.desktopmode;
 
 /**
- * Provides information on the current wifi activity.
+ * Interface that is exposed to remote callers to manipulate desktop mode features.
  */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+interface IDesktopMode {
+
+    /** Show apps on the desktop */
+    void showDesktopApps();
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
index 2aa933d..fbf326e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
@@ -29,19 +29,37 @@
 ### SysUI accessible components
 In addition to doing the above, you will also need to provide an interface for calling to SysUI
 from the Shell and vice versa.  The current pattern is to have a parallel `Optional<Component name>`
-interface that the `<Component name>Controller` implements and handles on the main Shell thread.
+interface that the `<Component name>Controller` implements and handles on the main Shell thread
+(see [SysUI/Shell threading](threading.md)).
 
 In addition, because components accessible to SysUI injection are explicitly listed, you'll have to
 add an appropriate method in `WMComponent` to get the interface and update the `Builder` in
 `SysUIComponent` to take the interface so it can be injected in SysUI code.  The binding between
 the two is done in `SystemUIFactory#init()` which will need to be updated as well.
 
+Specifically, to support calling into a controller from an external process (like Launcher):
+- Create an implementation of the external interface within the controller
+- Have all incoming calls post to the main shell thread (inject @ShellMainThread Executor into the
+  controller if needed)
+- Note that callbacks into SysUI should take an associated executor to call back on
+
 ### Launcher accessible components
 Because Launcher is not a part of SystemUI and is a separate process, exposing controllers to
 Launcher requires a new AIDL interface to be created and implemented by the controller.  The
 implementation of the stub interface in the controller otherwise behaves similar to the interface
 to SysUI where it posts the work to the main Shell thread.
 
+Specifically, to support calling into a controller from an external process (like Launcher):
+- Create an implementation of the interface binder's `Stub` class within the controller, have it
+  extend `ExternalInterfaceBinder` and implement `invalidate()` to ensure it doesn't hold long
+  references to the outer controller
+- Make the controller implement `RemoteCallable<T>`, and have all incoming calls use one of
+  the `ExecutorUtils.executeRemoteCallWithTaskPermission()` calls to verify the caller's identity
+  and ensure the call happens on the main shell thread and not the binder thread
+- Inject `ShellController` and add the instance of the implementation as external interface
+- In Launcher, update `TouchInteractionService` to pass the interface to `SystemUIProxy`, and then
+  call the SystemUIProxy method as needed in that code
+
 ### Component initialization
 To initialize the component:
 - On the Shell side, you potentially need to do two things to initialize the component:
@@ -64,8 +82,9 @@
 
 ### General Do's & Dont's
 Do:
-- Do add unit tests for all new components
-- Do keep controllers simple and break them down as needed
+- Add unit tests for all new components
+- Keep controllers simple and break them down as needed
+- Any SysUI callbacks should also take an associated executor to run the callback on
 
 Don't:
 - **Don't** do initialization in the constructor, only do initialization in the init callbacks.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java
index 9356660..f86d467 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasks.java
@@ -33,9 +33,4 @@
      * - If there is a floating task for this intent, and it's not stashed, this stashes it.
      */
     void showOrSetStashed(Intent intent);
-
-    /** Returns a binder that can be passed to an external process to manipulate FloatingTasks. */
-    default IFloatingTasks createExternalInterface() {
-        return null;
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java
index 6755299..b3c09d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java
@@ -21,6 +21,7 @@
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_FLOATING_APPS;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_FLOATING_TASKS;
 
 import android.annotation.Nullable;
 import android.content.Context;
@@ -40,6 +41,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.TaskViewTransitions;
 import com.android.wm.shell.bubbles.BubbleController;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
@@ -136,11 +138,13 @@
         if (isFloatingTasksEnabled()) {
             shellInit.addInitCallback(this::onInit, this);
         }
-        mShellCommandHandler.addDumpCallback(this::dump, this);
     }
 
     protected void onInit() {
         mShellController.addConfigurationChangeListener(this);
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_FLOATING_TASKS,
+                this::createExternalInterface, this);
+        mShellCommandHandler.addDumpCallback(this::dump, this);
     }
 
     /** Only used for testing. */
@@ -168,6 +172,10 @@
         return FLOATING_TASKS_ENABLED || mFloatingTasksEnabledForTests;
     }
 
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IFloatingTasksImpl(this);
+    }
+
     @Override
     public void onThemeChanged() {
         if (mIsFloatingLayerAdded) {
@@ -412,28 +420,18 @@
      */
     @ExternalThread
     private class FloatingTaskImpl implements FloatingTasks {
-        private IFloatingTasksImpl mIFloatingTasks;
-
         @Override
         public void showOrSetStashed(Intent intent) {
             mMainExecutor.execute(() -> FloatingTasksController.this.showOrSetStashed(intent));
         }
-
-        @Override
-        public IFloatingTasks createExternalInterface() {
-            if (mIFloatingTasks != null) {
-                mIFloatingTasks.invalidate();
-            }
-            mIFloatingTasks = new IFloatingTasksImpl(FloatingTasksController.this);
-            return mIFloatingTasks;
-        }
     }
 
     /**
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class IFloatingTasksImpl extends IFloatingTasks.Stub {
+    private static class IFloatingTasksImpl extends IFloatingTasks.Stub
+            implements ExternalInterfaceBinder {
         private FloatingTasksController mController;
 
         IFloatingTasksImpl(FloatingTasksController controller) {
@@ -443,7 +441,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
 
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 f58719b..f82a346 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
@@ -19,16 +19,12 @@
 import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_FREEFORM;
 
 import android.app.ActivityManager.RunningTaskInfo;
-import android.util.Log;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
-import android.window.TransitionInfo;
-
-import androidx.annotation.Nullable;
 
 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.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ShellInit;
@@ -41,31 +37,26 @@
 /**
  * {@link ShellTaskOrganizer.TaskListener} for {@link
  * ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}.
- *
- * @param <T> the type of window decoration instance
  */
-public class FreeformTaskListener<T extends AutoCloseable>
-        implements ShellTaskOrganizer.TaskListener {
+public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener {
     private static final String TAG = "FreeformTaskListener";
 
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
-    private final WindowDecorViewModel<T> mWindowDecorationViewModel;
+    private final WindowDecorViewModel mWindowDecorationViewModel;
 
-    private final SparseArray<State<T>> mTasks = new SparseArray<>();
-    private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
+    private final SparseArray<State> mTasks = new SparseArray<>();
 
-    private static class State<T extends AutoCloseable> {
+    private static class State {
         RunningTaskInfo mTaskInfo;
         SurfaceControl mLeash;
-        T mWindowDecoration;
     }
 
     public FreeformTaskListener(
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
             Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
-            WindowDecorViewModel<T> windowDecorationViewModel) {
+            WindowDecorViewModel windowDecorationViewModel) {
         mShellTaskOrganizer = shellTaskOrganizer;
         mWindowDecorationViewModel = windowDecorationViewModel;
         mDesktopModeTaskRepository = desktopModeTaskRepository;
@@ -80,77 +71,54 @@
 
     @Override
     public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
+        if (mTasks.get(taskInfo.taskId) != null) {
+            throw new IllegalStateException("Task appeared more than once: #" + taskInfo.taskId);
+        }
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Appeared: #%d",
                 taskInfo.taskId);
-        final State<T> state = createOrUpdateTaskState(taskInfo, leash);
+        final State state = new State();
+        state.mTaskInfo = taskInfo;
+        state.mLeash = leash;
+        mTasks.put(taskInfo.taskId, state);
         if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            state.mWindowDecoration =
-                    mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
+            mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
             t.apply();
         }
 
-        if (DesktopMode.IS_SUPPORTED && taskInfo.isVisible) {
+        if (DesktopModeStatus.IS_SUPPORTED && taskInfo.isVisible) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                     "Adding active freeform task: #%d", taskInfo.taskId);
             mDesktopModeTaskRepository.ifPresent(it -> it.addActiveTask(taskInfo.taskId));
         }
     }
 
-    private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
-        State<T> state = mTasks.get(taskInfo.taskId);
-        if (state != null) {
-            updateTaskInfo(taskInfo);
-            return state;
-        }
-
-        state = new State<>();
-        state.mTaskInfo = taskInfo;
-        state.mLeash = leash;
-        mTasks.put(taskInfo.taskId, state);
-
-        return state;
-    }
-
     @Override
     public void onTaskVanished(RunningTaskInfo taskInfo) {
-        final State<T> state = mTasks.get(taskInfo.taskId);
-        if (state == null) {
-            // This is possible if the transition happens before this method.
-            return;
-        }
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Vanished: #%d",
                 taskInfo.taskId);
         mTasks.remove(taskInfo.taskId);
 
-        if (DesktopMode.IS_SUPPORTED) {
+        if (DesktopModeStatus.IS_SUPPORTED) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                     "Removing active freeform task: #%d", taskInfo.taskId);
             mDesktopModeTaskRepository.ifPresent(it -> it.removeActiveTask(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
-            // transition didn't happen, it'd be cleared when the next transition finished.
-            if (state.mWindowDecoration != null) {
-                mWindowDecorOfVanishedTasks.put(taskInfo.taskId, state.mWindowDecoration);
-            }
-            return;
+        if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
+            mWindowDecorationViewModel.destroyWindowDecoration(taskInfo);
         }
-        releaseWindowDecor(state.mWindowDecoration);
     }
 
     @Override
     public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
-        final State<T> state = updateTaskInfo(taskInfo);
+        final State state = mTasks.get(taskInfo.taskId);
+        state.mTaskInfo = taskInfo;
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Freeform Task Info Changed: #%d",
                 taskInfo.taskId);
-        if (state.mWindowDecoration != null) {
-            mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
-        }
+        mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo);
 
-        if (DesktopMode.IS_SUPPORTED) {
+        if (DesktopModeStatus.IS_SUPPORTED) {
             if (taskInfo.isVisible) {
                 ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                         "Adding active freeform task: #%d", taskInfo.taskId);
@@ -159,15 +127,6 @@
         }
     }
 
-    private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
-        final State<T> state = mTasks.get(taskInfo.taskId);
-        if (state == null) {
-            throw new RuntimeException("Task info changed before appearing: #" + taskInfo.taskId);
-        }
-        state.mTaskInfo = taskInfo;
-        return state;
-    }
-
     @Override
     public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) {
         b.setParent(findTaskSurface(taskId));
@@ -186,103 +145,6 @@
         return mTasks.get(taskId).mLeash;
     }
 
-    /**
-     * Creates a window decoration for a transition.
-     *
-     * @param change the change of this task transition that needs to have the task layer as the
-     *               leash
-     * @return {@code true} if it creates the window decoration; {@code false} otherwise
-     */
-    boolean createWindowDecoration(
-            TransitionInfo.Change change,
-            SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT) {
-        final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
-        if (state.mWindowDecoration != null) {
-            return false;
-        }
-        state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration(
-                state.mTaskInfo, state.mLeash, startT, finishT);
-        return true;
-    }
-
-    /**
-     * Gives out the ownership of the task's window decoration. The given task is leaving (of has
-     * left) this task listener. This is the transition system asking for the ownership.
-     *
-     * @param taskInfo the maximizing task
-     * @return the window decor of the maximizing task if any
-     */
-    T giveWindowDecoration(
-            RunningTaskInfo taskInfo,
-            SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT) {
-        T windowDecor;
-        final State<T> state = mTasks.get(taskInfo.taskId);
-        if (state != null) {
-            windowDecor = state.mWindowDecoration;
-            state.mWindowDecoration = null;
-        } else {
-            windowDecor =
-                    mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId);
-        }
-        if (windowDecor == null) {
-            return null;
-        }
-        mWindowDecorationViewModel.setupWindowDecorationForTransition(
-                taskInfo, startT, finishT, windowDecor);
-        return windowDecor;
-    }
-
-    /**
-     * Adopt the incoming window decoration and lets the window decoration prepare for a transition.
-     *
-     * @param change the change of this task transition that needs to have the task layer as the
-     *               leash
-     * @param startT the start transaction of this transition
-     * @param finishT the finish transaction of this transition
-     * @param windowDecor the window decoration to adopt
-     * @return {@code true} if it adopts the window decoration; {@code false} otherwise
-     */
-    boolean adoptWindowDecoration(
-            TransitionInfo.Change change,
-            SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT,
-            @Nullable AutoCloseable windowDecor) {
-        final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
-        state.mWindowDecoration = mWindowDecorationViewModel.adoptWindowDecoration(windowDecor);
-        if (state.mWindowDecoration != null) {
-            mWindowDecorationViewModel.setupWindowDecorationForTransition(
-                    state.mTaskInfo, startT, finishT, state.mWindowDecoration);
-            return true;
-        } else {
-            state.mWindowDecoration = mWindowDecorationViewModel.createWindowDecoration(
-                    state.mTaskInfo, state.mLeash, startT, finishT);
-            return false;
-        }
-    }
-
-    void onTaskTransitionFinished() {
-        if (mWindowDecorOfVanishedTasks.size() == 0) {
-            return;
-        }
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                "Clearing window decors of vanished tasks. There could be visual defects "
-                + "if any of them is used later in transitions.");
-        for (int i = 0; i < mWindowDecorOfVanishedTasks.size(); ++i) {
-            releaseWindowDecor(mWindowDecorOfVanishedTasks.valueAt(i));
-        }
-        mWindowDecorOfVanishedTasks.clear();
-    }
-
-    private void releaseWindowDecor(T windowDecor) {
-        try {
-            windowDecor.close();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to release window decoration.", e);
-        }
-    }
-
     @Override
     public void dump(PrintWriter pw, String prefix) {
         final String innerPrefix = prefix + "  ";
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 fd4c85fa..04fc79a 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
@@ -46,14 +46,14 @@
         implements Transitions.TransitionHandler, FreeformTaskTransitionStarter {
 
     private final Transitions mTransitions;
-    private final WindowDecorViewModel<?> mWindowDecorViewModel;
+    private final WindowDecorViewModel mWindowDecorViewModel;
 
     private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
 
     public FreeformTaskTransitionHandler(
             ShellInit shellInit,
             Transitions transitions,
-            WindowDecorViewModel<?> windowDecorViewModel) {
+            WindowDecorViewModel windowDecorViewModel) {
         mTransitions = transitions;
         mWindowDecorViewModel = windowDecorViewModel;
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 17d6067..f4888fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -16,13 +16,9 @@
 
 package com.android.wm.shell.freeform;
 
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.IBinder;
-import android.util.Log;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.TransitionInfo;
@@ -31,9 +27,9 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.wm.shell.fullscreen.FullscreenTaskListener;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -47,23 +43,19 @@
  * be a part of transitions.
  */
 public class FreeformTaskTransitionObserver implements Transitions.TransitionObserver {
-    private static final String TAG = "FreeformTO";
-
     private final Transitions mTransitions;
-    private final FreeformTaskListener<?> mFreeformTaskListener;
-    private final FullscreenTaskListener<?> mFullscreenTaskListener;
+    private final WindowDecorViewModel mWindowDecorViewModel;
 
-    private final Map<IBinder, List<AutoCloseable>> mTransitionToWindowDecors = new HashMap<>();
+    private final Map<IBinder, List<ActivityManager.RunningTaskInfo>> mTransitionToTaskInfo =
+            new HashMap<>();
 
     public FreeformTaskTransitionObserver(
             Context context,
             ShellInit shellInit,
             Transitions transitions,
-            FullscreenTaskListener<?> fullscreenTaskListener,
-            FreeformTaskListener<?> freeformTaskListener) {
+            WindowDecorViewModel windowDecorViewModel) {
         mTransitions = transitions;
-        mFreeformTaskListener = freeformTaskListener;
-        mFullscreenTaskListener = fullscreenTaskListener;
+        mWindowDecorViewModel = windowDecorViewModel;
         if (Transitions.ENABLE_SHELL_TRANSITIONS && FreeformComponents.isFreeformEnabled(context)) {
             shellInit.addInitCallback(this::onInit, this);
         }
@@ -80,7 +72,7 @@
             @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction startT,
             @NonNull SurfaceControl.Transaction finishT) {
-        final ArrayList<AutoCloseable> windowDecors = new ArrayList<>();
+        final ArrayList<ActivityManager.RunningTaskInfo> taskInfoList = new ArrayList<>();
         final ArrayList<WindowContainerToken> taskParents = new ArrayList<>();
         for (TransitionInfo.Change change : info.getChanges()) {
             if ((change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0) {
@@ -110,92 +102,40 @@
                     onOpenTransitionReady(change, startT, finishT);
                     break;
                 case WindowManager.TRANSIT_CLOSE: {
-                    onCloseTransitionReady(change, windowDecors, startT, finishT);
+                    taskInfoList.add(change.getTaskInfo());
+                    onCloseTransitionReady(change, startT, finishT);
                     break;
                 }
                 case WindowManager.TRANSIT_CHANGE:
-                    onChangeTransitionReady(info.getType(), change, startT, finishT);
+                    onChangeTransitionReady(change, startT, finishT);
                     break;
             }
         }
-        if (!windowDecors.isEmpty()) {
-            mTransitionToWindowDecors.put(transition, windowDecors);
-        }
+        mTransitionToTaskInfo.put(transition, taskInfoList);
     }
 
     private void onOpenTransitionReady(
             TransitionInfo.Change change,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        switch (change.getTaskInfo().getWindowingMode()){
-            case WINDOWING_MODE_FREEFORM:
-                mFreeformTaskListener.createWindowDecoration(change, startT, finishT);
-                break;
-            case WINDOWING_MODE_FULLSCREEN:
-                mFullscreenTaskListener.createWindowDecoration(change, startT, finishT);
-                break;
-        }
+        mWindowDecorViewModel.createWindowDecoration(
+                change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
     private void onCloseTransitionReady(
             TransitionInfo.Change change,
-            ArrayList<AutoCloseable> windowDecors,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        final AutoCloseable windowDecor;
-        switch (change.getTaskInfo().getWindowingMode()) {
-            case WINDOWING_MODE_FREEFORM:
-                windowDecor = mFreeformTaskListener.giveWindowDecoration(change.getTaskInfo(),
-                        startT, finishT);
-                break;
-            case WINDOWING_MODE_FULLSCREEN:
-                windowDecor = mFullscreenTaskListener.giveWindowDecoration(change.getTaskInfo(),
-                        startT, finishT);
-                break;
-            default:
-                windowDecor = null;
-        }
-        if (windowDecor != null) {
-            windowDecors.add(windowDecor);
-        }
+        mWindowDecorViewModel.setupWindowDecorationForTransition(
+                change.getTaskInfo(), startT, finishT);
     }
 
     private void onChangeTransitionReady(
-            int type,
             TransitionInfo.Change change,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        AutoCloseable windowDecor = null;
-
-        boolean adopted = false;
-        final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
-        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
-            windowDecor = mFreeformTaskListener.giveWindowDecoration(
-                    change.getTaskInfo(), startT, finishT);
-            if (windowDecor != null) {
-                adopted = mFullscreenTaskListener.adoptWindowDecoration(
-                        change, startT, finishT, windowDecor);
-            } else {
-                // will return false if it already has the window decor.
-                adopted = mFullscreenTaskListener.createWindowDecoration(change, startT, finishT);
-            }
-        }
-
-        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-            windowDecor = mFullscreenTaskListener.giveWindowDecoration(
-                    change.getTaskInfo(), startT, finishT);
-            if (windowDecor != null) {
-                adopted = mFreeformTaskListener.adoptWindowDecoration(
-                        change, startT, finishT, windowDecor);
-            } else {
-                // will return false if it already has the window decor.
-                adopted = mFreeformTaskListener.createWindowDecoration(change, startT, finishT);
-            }
-        }
-
-        if (!adopted) {
-            releaseWindowDecor(windowDecor);
-        }
+        mWindowDecorViewModel.setupWindowDecorationForTransition(
+                change.getTaskInfo(), startT, finishT);
     }
 
     @Override
@@ -203,43 +143,32 @@
 
     @Override
     public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
-        final List<AutoCloseable> windowDecorsOfMerged = mTransitionToWindowDecors.get(merged);
-        if (windowDecorsOfMerged == null) {
+        final List<ActivityManager.RunningTaskInfo> infoOfMerged =
+                mTransitionToTaskInfo.get(merged);
+        if (infoOfMerged == null) {
             // We are adding window decorations of the merged transition to them of the playing
             // transition so if there is none of them there is nothing to do.
             return;
         }
-        mTransitionToWindowDecors.remove(merged);
+        mTransitionToTaskInfo.remove(merged);
 
-        final List<AutoCloseable> windowDecorsOfPlaying = mTransitionToWindowDecors.get(playing);
-        if (windowDecorsOfPlaying != null) {
-            windowDecorsOfPlaying.addAll(windowDecorsOfMerged);
+        final List<ActivityManager.RunningTaskInfo> infoOfPlaying =
+                mTransitionToTaskInfo.get(playing);
+        if (infoOfPlaying != null) {
+            infoOfPlaying.addAll(infoOfMerged);
         } else {
-            mTransitionToWindowDecors.put(playing, windowDecorsOfMerged);
+            mTransitionToTaskInfo.put(playing, infoOfMerged);
         }
     }
 
     @Override
     public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {
-        final List<AutoCloseable> windowDecors = mTransitionToWindowDecors.getOrDefault(
-                transition, Collections.emptyList());
-        mTransitionToWindowDecors.remove(transition);
+        final List<ActivityManager.RunningTaskInfo> taskInfo =
+                mTransitionToTaskInfo.getOrDefault(transition, Collections.emptyList());
+        mTransitionToTaskInfo.remove(transition);
 
-        for (AutoCloseable windowDecor : windowDecors) {
-            releaseWindowDecor(windowDecor);
-        }
-        mFullscreenTaskListener.onTaskTransitionFinished();
-        mFreeformTaskListener.onTaskTransitionFinished();
-    }
-
-    private static void releaseWindowDecor(AutoCloseable windowDecor) {
-        if (windowDecor == null) {
-            return;
-        }
-        try {
-            windowDecor.close();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to release window decoration.", e);
+        for (int i = 0; i < taskInfo.size(); ++i) {
+            mWindowDecorViewModel.destroyWindowDecoration(taskInfo.get(i));
         }
     }
 }
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 76e296b..75a4091 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
@@ -22,13 +22,10 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.graphics.Point;
-import android.util.Log;
 import android.util.SparseArray;
 import android.view.SurfaceControl;
-import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -46,23 +43,20 @@
   * Organizes tasks presented in {@link android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN}.
  * @param <T> the type of window decoration instance
   */
-public class FullscreenTaskListener<T extends AutoCloseable>
-        implements ShellTaskOrganizer.TaskListener {
+public class FullscreenTaskListener implements ShellTaskOrganizer.TaskListener {
     private static final String TAG = "FullscreenTaskListener";
 
     private final ShellTaskOrganizer mShellTaskOrganizer;
 
-    private final SparseArray<State<T>> mTasks = new SparseArray<>();
-    private final SparseArray<T> mWindowDecorOfVanishedTasks = new SparseArray<>();
+    private final SparseArray<State> mTasks = new SparseArray<>();
 
-    private static class State<T extends AutoCloseable> {
+    private static class State {
         RunningTaskInfo mTaskInfo;
         SurfaceControl mLeash;
-        T mWindowDecoration;
     }
     private final SyncTransactionQueue mSyncQueue;
     private final Optional<RecentTasksController> mRecentTasksOptional;
-    private final Optional<WindowDecorViewModel<T>> mWindowDecorViewModelOptional;
+    private final Optional<WindowDecorViewModel> mWindowDecorViewModelOptional;
     /**
      * This constructor is used by downstream products.
      */
@@ -75,7 +69,7 @@
             ShellTaskOrganizer shellTaskOrganizer,
             SyncTransactionQueue syncQueue,
             Optional<RecentTasksController> recentTasksOptional,
-            Optional<WindowDecorViewModel<T>> windowDecorViewModelOptional) {
+            Optional<WindowDecorViewModel> windowDecorViewModelOptional) {
         mShellTaskOrganizer = shellTaskOrganizer;
         mSyncQueue = syncQueue;
         mRecentTasksOptional = recentTasksOptional;
@@ -98,21 +92,21 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Appeared: #%d",
                 taskInfo.taskId);
         final Point positionInParent = taskInfo.positionInParent;
-        final State<T> state = new State();
+        final State state = new State();
         state.mLeash = leash;
         state.mTaskInfo = taskInfo;
         mTasks.put(taskInfo.taskId, state);
 
         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
         updateRecentsForVisibleFullscreenTask(taskInfo);
+        boolean createdWindowDecor = false;
         if (mWindowDecorViewModelOptional.isPresent()) {
             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            state.mWindowDecoration =
-                    mWindowDecorViewModelOptional.get().createWindowDecoration(taskInfo,
-                            leash, t, t);
+            createdWindowDecor = mWindowDecorViewModelOptional.get()
+                    .createWindowDecoration(taskInfo, leash, t, t);
             t.apply();
         }
-        if (state.mWindowDecoration == null) {
+        if (!createdWindowDecor) {
             mSyncQueue.runInSync(t -> {
                 // Reset several properties back to fullscreen (PiP, for example, leaves all these
                 // properties in a bad state).
@@ -127,12 +121,11 @@
 
     @Override
     public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
-        final State<T> state = mTasks.get(taskInfo.taskId);
+        final State state = mTasks.get(taskInfo.taskId);
         final Point oldPositionInParent = state.mTaskInfo.positionInParent;
         state.mTaskInfo = taskInfo;
-        if (state.mWindowDecoration != null) {
-            mWindowDecorViewModelOptional.get().onTaskInfoChanged(
-                    state.mTaskInfo, state.mWindowDecoration);
+        if (mWindowDecorViewModelOptional.isPresent()) {
+            mWindowDecorViewModelOptional.get().onTaskInfoChanged(state.mTaskInfo);
         }
         if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
         updateRecentsForVisibleFullscreenTask(taskInfo);
@@ -147,160 +140,13 @@
 
     @Override
     public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
-        final State<T> state = mTasks.get(taskInfo.taskId);
-        if (state == null) {
-            // This is possible if the transition happens before this method.
-            return;
-        }
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, "Fullscreen Task Vanished: #%d",
                 taskInfo.taskId);
         mTasks.remove(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
-            // transition didn't happen, it'd be cleared when the next transition finished.
-            if (state.mWindowDecoration != null) {
-                mWindowDecorOfVanishedTasks.put(taskInfo.taskId, state.mWindowDecoration);
-            }
-            return;
-        }
-        releaseWindowDecor(state.mWindowDecoration);
-    }
-
-    /**
-     * Creates a window decoration for a transition.
-     *
-     * @param change the change of this task transition that needs to have the task layer as the
-     *               leash
-     * @return {@code true} if a decoration was actually created.
-     */
-    public boolean createWindowDecoration(TransitionInfo.Change change,
-            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT) {
-        final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
-        if (!mWindowDecorViewModelOptional.isPresent()) return false;
-        if (state.mWindowDecoration != null) {
-            // Already has a decoration.
-            return false;
-        }
-        T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration(
-                state.mTaskInfo, state.mLeash, startT, finishT);
-        if (newWindowDecor != null) {
-            state.mWindowDecoration = newWindowDecor;
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Adopt the incoming window decoration and lets the window decoration prepare for a transition.
-     *
-     * @param change the change of this task transition that needs to have the task layer as the
-     *               leash
-     * @param startT the start transaction of this transition
-     * @param finishT the finish transaction of this transition
-     * @param windowDecor the window decoration to adopt
-     * @return {@code true} if it adopts the window decoration; {@code false} otherwise
-     */
-    public boolean adoptWindowDecoration(
-            TransitionInfo.Change change,
-            SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT,
-            @Nullable AutoCloseable windowDecor) {
-        if (!mWindowDecorViewModelOptional.isPresent()) {
-            return false;
-        }
-        final State<T> state = createOrUpdateTaskState(change.getTaskInfo(), change.getLeash());
-        state.mWindowDecoration = mWindowDecorViewModelOptional.get().adoptWindowDecoration(
-                windowDecor);
-        if (state.mWindowDecoration != null) {
-            mWindowDecorViewModelOptional.get().setupWindowDecorationForTransition(
-                    state.mTaskInfo, startT, finishT, state.mWindowDecoration);
-            return true;
-        } else {
-            T newWindowDecor = mWindowDecorViewModelOptional.get().createWindowDecoration(
-                    state.mTaskInfo, state.mLeash, startT, finishT);
-            if (newWindowDecor != null) {
-                state.mWindowDecoration = newWindowDecor;
-            }
-            return false;
-        }
-    }
-
-    /**
-     * Clear window decors of vanished tasks.
-     */
-    public void onTaskTransitionFinished() {
-        if (mWindowDecorOfVanishedTasks.size() == 0) {
-            return;
-        }
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                "Clearing window decors of vanished tasks. There could be visual defects "
-                + "if any of them is used later in transitions.");
-        for (int i = 0; i < mWindowDecorOfVanishedTasks.size(); ++i) {
-            releaseWindowDecor(mWindowDecorOfVanishedTasks.valueAt(i));
-        }
-        mWindowDecorOfVanishedTasks.clear();
-    }
-
-    /**
-     * Gives out the ownership of the task's window decoration. The given task is leaving (of has
-     * left) this task listener. This is the transition system asking for the ownership.
-     *
-     * @param taskInfo the maximizing task
-     * @return the window decor of the maximizing task if any
-     */
-    public T giveWindowDecoration(
-            ActivityManager.RunningTaskInfo taskInfo,
-            SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT) {
-        T windowDecor;
-        final State<T> state = mTasks.get(taskInfo.taskId);
-        if (state != null) {
-            windowDecor = state.mWindowDecoration;
-            state.mWindowDecoration = null;
-        } else {
-            windowDecor =
-                    mWindowDecorOfVanishedTasks.removeReturnOld(taskInfo.taskId);
-        }
-        if (mWindowDecorViewModelOptional.isPresent() && windowDecor != null) {
-            mWindowDecorViewModelOptional.get().setupWindowDecorationForTransition(
-                    taskInfo, startT, finishT, windowDecor);
-        }
-
-        return windowDecor;
-    }
-
-    private State<T> createOrUpdateTaskState(ActivityManager.RunningTaskInfo taskInfo,
-            SurfaceControl leash) {
-        State<T> state = mTasks.get(taskInfo.taskId);
-        if (state != null) {
-            updateTaskInfo(taskInfo);
-            return state;
-        }
-
-        state = new State<T>();
-        state.mTaskInfo = taskInfo;
-        state.mLeash = leash;
-        mTasks.put(taskInfo.taskId, state);
-
-        return state;
-    }
-
-    private State<T> updateTaskInfo(ActivityManager.RunningTaskInfo taskInfo) {
-        final State<T> state = mTasks.get(taskInfo.taskId);
-        state.mTaskInfo = taskInfo;
-        return state;
-    }
-
-    private void releaseWindowDecor(T windowDecor) {
-        if (windowDecor == null) {
-            return;
-        }
-        try {
-            windowDecor.close();
-        } catch (Exception e) {
-            Log.e(TAG, "Failed to release window decoration.", e);
+        if (Transitions.ENABLE_SHELL_TRANSITIONS) return;
+        if (mWindowDecorViewModelOptional.isPresent()) {
+            mWindowDecorViewModelOptional.get().destroyWindowDecoration(taskInfo);
         }
     }
 
@@ -342,6 +188,4 @@
     public String toString() {
         return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_FULLSCREEN);
     }
-
-
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index 7129165..2ee3348 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -30,13 +30,6 @@
             OneHandedController.SUPPORT_ONE_HANDED_MODE, false);
 
     /**
-     * Returns a binder that can be passed to an external process to manipulate OneHanded.
-     */
-    default IOneHanded createExternalInterface() {
-        return null;
-    }
-
-    /**
      * Enters one handed mode.
      */
     void startOneHanded();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index e0c4fe8..679d4ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -24,6 +24,7 @@
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED;
 
 import android.annotation.BinderThread;
 import android.content.ComponentName;
@@ -49,6 +50,7 @@
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerCallback;
@@ -296,12 +298,18 @@
         mShellController.addConfigurationChangeListener(this);
         mShellController.addKeyguardChangeListener(this);
         mShellController.addUserChangeListener(this);
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_ONE_HANDED,
+                this::createExternalInterface, this);
     }
 
     public OneHanded asOneHanded() {
         return mImpl;
     }
 
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IOneHandedImpl(this);
+    }
+
     @Override
     public Context getContext() {
         return mContext;
@@ -709,17 +717,6 @@
      */
     @ExternalThread
     private class OneHandedImpl implements OneHanded {
-        private IOneHandedImpl mIOneHanded;
-
-        @Override
-        public IOneHanded createExternalInterface() {
-            if (mIOneHanded != null) {
-                mIOneHanded.invalidate();
-            }
-            mIOneHanded = new IOneHandedImpl(OneHandedController.this);
-            return mIOneHanded;
-        }
-
         @Override
         public void startOneHanded() {
             mMainExecutor.execute(() -> {
@@ -767,7 +764,7 @@
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class IOneHandedImpl extends IOneHanded.Stub {
+    private static class IOneHandedImpl extends IOneHanded.Stub implements ExternalInterfaceBinder {
         private OneHandedController mController;
 
         IOneHandedImpl(OneHandedController controller) {
@@ -777,7 +774,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
 
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 4def15d..2624ee5 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
@@ -59,10 +59,15 @@
     /**
      * Sets listener to get pinned stack animation callbacks.
      */
-    oneway void setPinnedStackAnimationListener(IPipAnimationListener listener) = 3;
+    oneway void setPipAnimationListener(IPipAnimationListener listener) = 3;
 
     /**
      * Sets the shelf height and visibility.
      */
     oneway void setShelfHeight(boolean visible, int shelfHeight) = 4;
+
+    /**
+     * Sets the next pip animation type to be the alpha animation.
+     */
+    oneway void setPipAnimationTypeToAlpha() = 5;
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
index c06881a..f34d2a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java
@@ -27,14 +27,6 @@
  */
 @ExternalThread
 public interface Pip {
-
-    /**
-     * Returns a binder that can be passed to an external process to manipulate PIP.
-     */
-    default IPip createExternalInterface() {
-        return null;
-    }
-
     /**
      * Expand PIP, it's possible that specific request to activate the window via Alt-tab.
      */
@@ -51,15 +43,6 @@
     }
 
     /**
-     * Sets both shelf visibility and its height.
-     *
-     * @param visible visibility of shelf.
-     * @param height  to specify the height for shelf.
-     */
-    default void setShelfHeight(boolean visible, int height) {
-    }
-
-    /**
      * Set the callback when {@link PipTaskOrganizer#isInPip()} state is changed.
      *
      * @param callback The callback accepts the result of {@link PipTaskOrganizer#isInPip()}
@@ -68,14 +51,6 @@
     default void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {}
 
     /**
-     * Set the pinned stack with {@link PipAnimationController.AnimationType}
-     *
-     * @param animationType The pre-defined {@link PipAnimationController.AnimationType}
-     */
-    default void setPinnedStackAnimationType(int animationType) {
-    }
-
-    /**
      * Called when showing Pip menu.
      */
     default void showPictureInPictureMenu() {}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index b32c3ee..6728c00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -195,6 +195,17 @@
     }
 
     /**
+     * Returns true if the PiP window is currently being animated.
+     */
+    public boolean isAnimating() {
+        PipAnimationController.PipTransitionAnimator animator = getCurrentAnimator();
+        if (animator != null && animator.isRunning()) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Quietly cancel the animator by removing the listeners first.
      */
     static void quietCancel(@NonNull ValueAnimator animator) {
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 1a52d8c..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
@@ -324,19 +324,6 @@
         return mPipTransitionController;
     }
 
-    /**
-     * Returns true if the PiP window is currently being animated.
-     */
-    public boolean isAnimating() {
-        // TODO(b/183746978) move this to PipAnimationController, and inject that in PipController
-        PipAnimationController.PipTransitionAnimator animator =
-                mPipAnimationController.getCurrentAnimator();
-        if (animator != null && animator.isRunning()) {
-            return true;
-        }
-        return false;
-    }
-
     public Rect getCurrentOrAnimatingBounds() {
         PipAnimationController.PipTransitionAnimator animator =
                 mPipAnimationController.getCurrentAnimator();
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 bc8191d..30124a5 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
@@ -23,6 +23,7 @@
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_PIP_TRANSITION;
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP_TO_SPLIT_SCREEN;
@@ -32,6 +33,7 @@
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_TO_PIP;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_USER_RESIZE;
 import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -67,6 +69,7 @@
 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.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SingleInstanceRemoteListener;
@@ -130,6 +133,7 @@
     private DisplayController mDisplayController;
     private PipInputConsumer mPipInputConsumer;
     private WindowManagerShellWrapper mWindowManagerShellWrapper;
+    private PipAnimationController mPipAnimationController;
     private PipAppOpsListener mAppOpsListener;
     private PipMediaController mMediaController;
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
@@ -157,8 +161,12 @@
             // early bail out if the keep clear areas feature is disabled
             return;
         }
+        if (mPipBoundsState.isStashed()) {
+            // don't move when stashed
+            return;
+        }
         // if there is another animation ongoing, wait for it to finish and try again
-        if (mPipTaskOrganizer.isAnimating()) {
+        if (mPipAnimationController.isAnimating()) {
             mMainExecutor.removeCallbacks(
                     mMovePipInResponseToKeepClearAreasChangeCallback);
             mMainExecutor.executeDelayed(
@@ -368,6 +376,7 @@
             ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
+            PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipKeepClearAlgorithm pipKeepClearAlgorithm,
@@ -392,11 +401,12 @@
         }
 
         return new PipController(context, shellInit, shellCommandHandler, shellController,
-                displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm,
-                pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
-                pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
-                windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                displayInsetsController, oneHandedController, mainExecutor)
+                displayController, pipAnimationController, pipAppOpsListener,
+                pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper,
+                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
+                pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
+                taskStackListener, pipParamsChangedForwarder, displayInsetsController,
+                oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -405,6 +415,7 @@
             ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
+            PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipKeepClearAlgorithm pipKeepClearAlgorithm,
@@ -445,6 +456,7 @@
         mMediaController = pipMediaController;
         mMenuController = phonePipMenuController;
         mTouchHandler = pipTouchHandler;
+        mPipAnimationController = pipAnimationController;
         mAppOpsListener = pipAppOpsListener;
         mOneHandedController = oneHandedController;
         mPipTransitionController = pipTransitionController;
@@ -626,6 +638,12 @@
         mShellController.addConfigurationChangeListener(this);
         mShellController.addKeyguardChangeListener(this);
         mShellController.addUserChangeListener(this);
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_PIP,
+                this::createExternalInterface, this);
+    }
+
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IPipImpl(this);
     }
 
     @Override
@@ -1034,17 +1052,6 @@
      * The interface for calls from outside the Shell, within the host process.
      */
     private class PipImpl implements Pip {
-        private IPipImpl mIPip;
-
-        @Override
-        public IPip createExternalInterface() {
-            if (mIPip != null) {
-                mIPip.invalidate();
-            }
-            mIPip = new IPipImpl(PipController.this);
-            return mIPip;
-        }
-
         @Override
         public void expandPip() {
             mMainExecutor.execute(() -> {
@@ -1060,13 +1067,6 @@
         }
 
         @Override
-        public void setShelfHeight(boolean visible, int height) {
-            mMainExecutor.execute(() -> {
-                PipController.this.setShelfHeight(visible, height);
-            });
-        }
-
-        @Override
         public void setOnIsInPipStateChangedListener(Consumer<Boolean> callback) {
             mMainExecutor.execute(() -> {
                 PipController.this.setOnIsInPipStateChangedListener(callback);
@@ -1074,13 +1074,6 @@
         }
 
         @Override
-        public void setPinnedStackAnimationType(int animationType) {
-            mMainExecutor.execute(() -> {
-                PipController.this.setPinnedStackAnimationType(animationType);
-            });
-        }
-
-        @Override
         public void addPipExclusionBoundsChangeListener(Consumer<Rect> listener) {
             mMainExecutor.execute(() -> {
                 mPipBoundsState.addPipExclusionBoundsChangeCallback(listener);
@@ -1106,7 +1099,7 @@
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class IPipImpl extends IPip.Stub {
+    private static class IPipImpl extends IPip.Stub implements ExternalInterfaceBinder {
         private PipController mController;
         private final SingleInstanceRemoteListener<PipController,
                 IPipAnimationListener> mListener;
@@ -1137,7 +1130,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
 
@@ -1173,8 +1167,8 @@
         }
 
         @Override
-        public void setPinnedStackAnimationListener(IPipAnimationListener listener) {
-            executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener",
+        public void setPipAnimationListener(IPipAnimationListener listener) {
+            executeRemoteCallWithTaskPermission(mController, "setPipAnimationListener",
                     (controller) -> {
                         if (listener != null) {
                             mListener.register(listener);
@@ -1183,5 +1177,13 @@
                         }
                     });
         }
+
+        @Override
+        public void setPipAnimationTypeToAlpha() {
+            executeRemoteCallWithTaskPermission(mController, "setPipAnimationTypeToAlpha",
+                    (controller) -> {
+                        controller.setPinnedStackAnimationType(ANIM_TYPE_ALPHA);
+                    });
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
index 552ebde..93ffb3d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
@@ -17,22 +17,14 @@
 package com.android.wm.shell.protolog;
 
 import android.annotation.Nullable;
-import android.content.Context;
-import android.util.Log;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.BaseProtoLogImpl;
 import com.android.internal.protolog.ProtoLogViewerConfigReader;
 import com.android.internal.protolog.common.IProtoLogGroup;
-import com.android.wm.shell.R;
 
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
 import java.io.PrintWriter;
 
-import org.json.JSONException;
-
 
 /**
  * A service for the ProtoLog logging system.
@@ -40,8 +32,9 @@
 public class ShellProtoLogImpl extends BaseProtoLogImpl {
     private static final String TAG = "ProtoLogImpl";
     private static final int BUFFER_CAPACITY = 1024 * 1024;
-    // TODO: Get the right path for the proto log file when we initialize the shell components
-    private static final String LOG_FILENAME = new File("wm_shell_log.pb").getAbsolutePath();
+    // TODO: find a proper location to save the protolog message file
+    private static final String LOG_FILENAME = "/data/misc/wmtrace/shell_log.winscope";
+    private static final String VIEWER_CONFIG_FILENAME = "/system_ext/etc/wmshell.protolog.json.gz";
 
     private static ShellProtoLogImpl sServiceInstance = null;
 
@@ -111,18 +104,8 @@
     }
 
     public int startTextLogging(String[] groups, PrintWriter pw) {
-        try (InputStream is =
-                     getClass().getClassLoader().getResourceAsStream("wm_shell_protolog.json")){
-            mViewerConfig.loadViewerConfig(is);
-            return setLogging(true /* setTextLogging */, true, pw, groups);
-        } catch (IOException e) {
-            Log.i(TAG, "Unable to load log definitions: IOException while reading "
-                    + "wm_shell_protolog. " + e);
-        } catch (JSONException e) {
-            Log.i(TAG, "Unable to load log definitions: JSON parsing exception while reading "
-                    + "wm_shell_protolog. " + e);
-        }
-        return -1;
+        mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME);
+        return setLogging(true /* setTextLogging */, true, pw, groups);
     }
 
     public int stopTextLogging(String[] groups, PrintWriter pw) {
@@ -130,7 +113,8 @@
     }
 
     private ShellProtoLogImpl() {
-        super(new File(LOG_FILENAME), null, BUFFER_CAPACITY, new ProtoLogViewerConfigReader());
+        super(new File(LOG_FILENAME), VIEWER_CONFIG_FILENAME, BUFFER_CAPACITY,
+                new ProtoLogViewerConfigReader());
     }
 }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java
index a5748f6..069066e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasks.java
@@ -17,6 +17,11 @@
 package com.android.wm.shell.recents;
 
 import com.android.wm.shell.common.annotations.ExternalThread;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Interface for interacting with the recent tasks.
@@ -24,9 +29,9 @@
 @ExternalThread
 public interface RecentTasks {
     /**
-     * Returns a binder that can be passed to an external process to fetch recent tasks.
+     * Gets the set of recent tasks.
      */
-    default IRecentTasks createExternalInterface() {
-        return null;
+    default void getRecentTasks(int maxNum, int flags, int userId, Executor callbackExecutor,
+            Consumer<List<GroupedRecentTaskInfo>> callback) {
     }
 }
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 f879994..08f3db6 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
@@ -20,6 +20,7 @@
 import static android.content.pm.PackageManager.FEATURE_PC;
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
 
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
@@ -37,6 +38,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SingleInstanceRemoteListener;
@@ -44,10 +46,11 @@
 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.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 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.util.GroupedRecentTaskInfo;
 import com.android.wm.shell.util.SplitBounds;
@@ -58,6 +61,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Manages the recent task list from the system, caching it as necessary.
@@ -67,11 +72,13 @@
     private static final String TAG = RecentTasksController.class.getSimpleName();
 
     private final Context mContext;
+    private final ShellController mShellController;
     private final ShellCommandHandler mShellCommandHandler;
     private final Optional<DesktopModeTaskRepository> mDesktopModeTaskRepository;
     private final ShellExecutor mMainExecutor;
     private final TaskStackListenerImpl mTaskStackListener;
-    private final RecentTasks mImpl = new RecentTasksImpl();
+    private final RecentTasksImpl mImpl = new RecentTasksImpl();
+    private final ActivityTaskManager mActivityTaskManager;
     private IRecentTasksListener mListener;
     private final boolean mIsDesktopMode;
 
@@ -94,26 +101,32 @@
     public static RecentTasksController create(
             Context context,
             ShellInit shellInit,
+            ShellController shellController,
             ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
+            ActivityTaskManager activityTaskManager,
             Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
         if (!context.getResources().getBoolean(com.android.internal.R.bool.config_hasRecents)) {
             return null;
         }
-        return new RecentTasksController(context, shellInit, shellCommandHandler, taskStackListener,
-                desktopModeTaskRepository, mainExecutor);
+        return new RecentTasksController(context, shellInit, shellController, shellCommandHandler,
+                taskStackListener, activityTaskManager, desktopModeTaskRepository, mainExecutor);
     }
 
     RecentTasksController(Context context,
             ShellInit shellInit,
+            ShellController shellController,
             ShellCommandHandler shellCommandHandler,
             TaskStackListenerImpl taskStackListener,
+            ActivityTaskManager activityTaskManager,
             Optional<DesktopModeTaskRepository> desktopModeTaskRepository,
             ShellExecutor mainExecutor) {
         mContext = context;
+        mShellController = shellController;
         mShellCommandHandler = shellCommandHandler;
+        mActivityTaskManager = activityTaskManager;
         mIsDesktopMode = mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
         mTaskStackListener = taskStackListener;
         mDesktopModeTaskRepository = desktopModeTaskRepository;
@@ -125,7 +138,13 @@
         return mImpl;
     }
 
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IRecentTasksImpl(this);
+    }
+
     private void onInit() {
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_RECENT_TASKS,
+                this::createExternalInterface, this);
         mShellCommandHandler.addDumpCallback(this::dump, this);
         mTaskStackListener.addListener(this);
         mDesktopModeTaskRepository.ifPresent(it -> it.addListener(this));
@@ -270,15 +289,10 @@
     }
 
     @VisibleForTesting
-    List<ActivityManager.RecentTaskInfo> getRawRecentTasks(int maxNum, int flags, int userId) {
-        return ActivityTaskManager.getInstance().getRecentTasks(maxNum, flags, userId);
-    }
-
-    @VisibleForTesting
     ArrayList<GroupedRecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
         // Note: the returned task list is from the most-recent to least-recent order
-        final List<ActivityManager.RecentTaskInfo> rawList = getRawRecentTasks(maxNum, flags,
-                userId);
+        final List<ActivityManager.RecentTaskInfo> rawList = mActivityTaskManager.getRecentTasks(
+                maxNum, flags, userId);
 
         // Make a mapping of task id -> task info
         final SparseArray<ActivityManager.RecentTaskInfo> rawMapping = new SparseArray<>();
@@ -287,7 +301,7 @@
             rawMapping.put(taskInfo.taskId, taskInfo);
         }
 
-        boolean desktopModeActive = DesktopMode.isActive(mContext);
+        boolean desktopModeActive = DesktopModeStatus.isActive(mContext);
         ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>();
 
         // Pull out the pairs as we iterate back in the list
@@ -320,7 +334,6 @@
 
         // 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])));
         }
@@ -336,8 +349,9 @@
         if (componentName == null) {
             return null;
         }
-        List<ActivityManager.RecentTaskInfo> tasks = getRawRecentTasks(Integer.MAX_VALUE,
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE, ActivityManager.getCurrentUser());
+        List<ActivityManager.RecentTaskInfo> tasks = mActivityTaskManager.getRecentTasks(
+                Integer.MAX_VALUE, ActivityManager.RECENT_IGNORE_UNAVAILABLE,
+                ActivityManager.getCurrentUser());
         for (int i = 0; i < tasks.size(); i++) {
             final ActivityManager.RecentTaskInfo task = tasks.get(i);
             if (task.isVisible) {
@@ -365,15 +379,14 @@
      */
     @ExternalThread
     private class RecentTasksImpl implements RecentTasks {
-        private IRecentTasksImpl mIRecentTasks;
-
         @Override
-        public IRecentTasks createExternalInterface() {
-            if (mIRecentTasks != null) {
-                mIRecentTasks.invalidate();
-            }
-            mIRecentTasks = new IRecentTasksImpl(RecentTasksController.this);
-            return mIRecentTasks;
+        public void getRecentTasks(int maxNum, int flags, int userId, Executor executor,
+                Consumer<List<GroupedRecentTaskInfo>> callback) {
+            mMainExecutor.execute(() -> {
+                List<GroupedRecentTaskInfo> tasks =
+                        RecentTasksController.this.getRecentTasks(maxNum, flags, userId);
+                executor.execute(() -> callback.accept(tasks));
+            });
         }
     }
 
@@ -382,7 +395,8 @@
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class IRecentTasksImpl extends IRecentTasks.Stub {
+    private static class IRecentTasksImpl extends IRecentTasks.Stub
+            implements ExternalInterfaceBinder {
         private RecentTasksController mController;
         private final SingleInstanceRemoteListener<RecentTasksController,
                 IRecentTasksListener> mListener;
@@ -413,7 +427,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
 
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 ecdafa9..eb08d0e 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
@@ -79,26 +79,47 @@
     /**
      * Starts tasks simultaneously in one transition.
      */
-    oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
-            in Bundle sideOptions, int sidePosition, float splitRatio,
-            in RemoteTransition remoteTransition, in InstanceId instanceId) = 10;
+    oneway void startTasks(int taskId1, in Bundle options1, int taskId2, in Bundle options2,
+            int splitPosition, float splitRatio, in RemoteTransition remoteTransition,
+            in InstanceId instanceId) = 10;
+
+    /**
+     * Starts a pair of intent and task in one transition.
+     */
+    oneway void startIntentAndTask(in PendingIntent pendingIntent, in Intent fillInIntent,
+            in Bundle options1, int taskId, in Bundle options2, int sidePosition, float splitRatio,
+            in RemoteTransition remoteTransition, in InstanceId instanceId) = 16;
+
+    /**
+     * Starts a pair of shortcut and task in one transition.
+     */
+    oneway void startShortcutAndTask(in ShortcutInfo shortcutInfo, in Bundle options1, int taskId,
+            in Bundle options2, int splitPosition, float splitRatio,
+             in RemoteTransition remoteTransition, in InstanceId instanceId) = 17;
 
     /**
      * Version of startTasks using legacy transition system.
      */
-    oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
-            int sideTaskId, in Bundle sideOptions, int sidePosition,
-            float splitRatio, in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 11;
+    oneway void startTasksWithLegacyTransition(int taskId1, in Bundle options1, int taskId2,
+            in Bundle options2, int splitPosition, float splitRatio,
+            in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 11;
 
     /**
      * Starts a pair of intent and task using legacy transition system.
      */
     oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
-            in Intent fillInIntent, int taskId, in Bundle mainOptions,in Bundle sideOptions,
-            int sidePosition, float splitRatio, in RemoteAnimationAdapter adapter,
+            in Intent fillInIntent, in Bundle options1, int taskId, in Bundle options2,
+            int splitPosition, float splitRatio, in RemoteAnimationAdapter adapter,
             in InstanceId instanceId) = 12;
 
     /**
+     * Starts a pair of shortcut and task using legacy transition system.
+     */
+    oneway void startShortcutAndTaskWithLegacyTransition(in ShortcutInfo shortcutInfo,
+            in Bundle options1, int taskId, in Bundle options2, int splitPosition, float splitRatio,
+            in RemoteAnimationAdapter adapter, in InstanceId instanceId) = 15;
+
+    /**
      * Blocking call that notifies and gets additional split-screen targets when entering
      * recents (for example: the dividerBar).
      * @param appTargets apps that will be re-parented to display area
@@ -111,11 +132,5 @@
      * 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, in InstanceId instanceId) = 15;
 }
+// Last id = 17
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
index e73b799..d86aadc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreen.java
@@ -70,13 +70,6 @@
     /** Unregisters listener that gets split screen callback. */
     void unregisterSplitScreenListener(@NonNull SplitScreenListener listener);
 
-    /**
-     * Returns a binder that can be passed to an external process to manipulate SplitScreen.
-     */
-    default ISplitScreen createExternalInterface() {
-        return null;
-    }
-
     /** Called when device waking up finished. */
     void onFinishedWakingUp();
 
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 07a6895..c6a2b83 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
@@ -29,6 +29,7 @@
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_UNDEFINED;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN;
 import static com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS;
 
 import android.app.ActivityManager;
@@ -71,6 +72,7 @@
 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.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SingleInstanceRemoteListener;
@@ -214,6 +216,10 @@
         return mImpl;
     }
 
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new ISplitScreenImpl(this);
+    }
+
     /**
      * This will be called after ShellTaskOrganizer has initialized/registered because of the
      * dependency order.
@@ -224,6 +230,8 @@
         mShellCommandHandler.addCommandCallback("splitscreen", mSplitScreenShellCommandHandler,
                 this);
         mShellController.addKeyguardChangeListener(this);
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_SPLIT_SCREEN,
+                this::createExternalInterface, this);
         if (mStageCoordinator == null) {
             // TODO: Multi-display
             mStageCoordinator = createStageCoordinator();
@@ -658,7 +666,6 @@
      */
     @ExternalThread
     private class SplitScreenImpl implements SplitScreen {
-        private ISplitScreenImpl mISplitScreen;
         private final ArrayMap<SplitScreenListener, Executor> mExecutors = new ArrayMap<>();
         private final SplitScreen.SplitScreenListener mListener = new SplitScreenListener() {
             @Override
@@ -704,15 +711,6 @@
         };
 
         @Override
-        public ISplitScreen createExternalInterface() {
-            if (mISplitScreen != null) {
-                mISplitScreen.invalidate();
-            }
-            mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
-            return mISplitScreen;
-        }
-
-        @Override
         public void registerSplitScreenListener(SplitScreenListener listener, Executor executor) {
             if (mExecutors.containsKey(listener)) return;
 
@@ -752,7 +750,8 @@
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class ISplitScreenImpl extends ISplitScreen.Stub {
+    private static class ISplitScreenImpl extends ISplitScreen.Stub
+            implements ExternalInterfaceBinder {
         private SplitScreenController mController;
         private final SingleInstanceRemoteListener<SplitScreenController,
                 ISplitScreenListener> mListener;
@@ -779,7 +778,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
 
@@ -828,47 +828,68 @@
         }
 
         @Override
-        public void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
-                int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
+        public void startTasksWithLegacyTransition(int taskId1, @Nullable Bundle options1,
+                int taskId2, @Nullable Bundle options2, @SplitPosition int splitPosition,
                 float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController, "startTasks",
                     (controller) -> controller.mStageCoordinator.startTasksWithLegacyTransition(
-                            mainTaskId, mainOptions, sideTaskId, sideOptions, sidePosition,
+                            taskId1, options1, taskId2, options2, splitPosition,
                             splitRatio, adapter, instanceId));
         }
 
         @Override
         public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
-                Intent fillInIntent, int taskId, Bundle mainOptions, Bundle sideOptions,
-                int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+                Intent fillInIntent, Bundle options1, int taskId, Bundle options2,
+                int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
                 InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController,
                     "startIntentAndTaskWithLegacyTransition", (controller) ->
                             controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
-                                    pendingIntent, fillInIntent, taskId, mainOptions, sideOptions,
-                                    sidePosition, splitRatio, adapter, instanceId));
+                                    pendingIntent, fillInIntent, options1, taskId, options2,
+                                    splitPosition, splitRatio, adapter, instanceId));
         }
 
         @Override
         public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
-                int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
-                @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+                @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
+                @SplitPosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
                 InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController,
                     "startShortcutAndTaskWithLegacyTransition", (controller) ->
                             controller.mStageCoordinator.startShortcutAndTaskWithLegacyTransition(
-                                    shortcutInfo, taskId, mainOptions, sideOptions, sidePosition,
+                                    shortcutInfo, options1, taskId, options2, splitPosition,
                                     splitRatio, adapter, instanceId));
         }
 
         @Override
-        public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
-                int sideTaskId, @Nullable Bundle sideOptions,
-                @SplitPosition int sidePosition, float splitRatio,
+        public void startTasks(int taskId1, @Nullable Bundle options1, int taskId2,
+                @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio,
                 @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
             executeRemoteCallWithTaskPermission(mController, "startTasks",
-                    (controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
-                            sideTaskId, sideOptions, sidePosition, splitRatio, remoteTransition,
+                    (controller) -> controller.mStageCoordinator.startTasks(taskId1, options1,
+                            taskId2, options2, splitPosition, splitRatio, remoteTransition,
+                            instanceId));
+        }
+
+        @Override
+        public void startIntentAndTask(PendingIntent pendingIntent, Intent fillInIntent,
+                @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
+                @SplitPosition int splitPosition, float splitRatio,
+                @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+            executeRemoteCallWithTaskPermission(mController, "startIntentAndTask",
+                    (controller) -> controller.mStageCoordinator.startIntentAndTask(pendingIntent,
+                            fillInIntent, options1, taskId, options2, splitPosition, splitRatio,
+                            remoteTransition, instanceId));
+        }
+
+        @Override
+        public void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1,
+                int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
+                float splitRatio, @Nullable RemoteTransition remoteTransition,
+                InstanceId instanceId) {
+            executeRemoteCallWithTaskPermission(mController, "startShortcutAndTask",
+                    (controller) -> controller.mStageCoordinator.startShortcutAndTask(shortcutInfo,
+                            options1, taskId, options2, splitPosition, splitRatio, remoteTransition,
                             instanceId));
         }
 
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 c17f822..9102bd3 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
@@ -516,14 +516,55 @@
     }
 
     /** Starts 2 tasks in one transition. */
-    void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
-            @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
+    void startTasks(int taskId1, @Nullable Bundle options1, int taskId2,
+            @Nullable Bundle options2, @SplitPosition int splitPosition, float splitRatio,
             @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        mainOptions = mainOptions != null ? mainOptions : new Bundle();
-        sideOptions = sideOptions != null ? sideOptions : new Bundle();
-        setSideStagePosition(sidePosition, wct);
+        setSideStagePosition(splitPosition, wct);
+        options1 = options1 != null ? options1 : new Bundle();
+        addActivityOptions(options1, mSideStage);
+        wct.startTask(taskId1, options1);
 
+        startWithTask(wct, taskId2, options2, splitRatio, remoteTransition, instanceId);
+    }
+
+    /** Start an intent and a task to a split pair in one transition. */
+    void startIntentAndTask(PendingIntent pendingIntent, Intent fillInIntent,
+            @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
+            @SplitPosition int splitPosition, float splitRatio,
+            @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        setSideStagePosition(splitPosition, wct);
+        options1 = options1 != null ? options1 : new Bundle();
+        addActivityOptions(options1, mSideStage);
+        wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
+
+        startWithTask(wct, taskId, options2, splitRatio, remoteTransition, instanceId);
+    }
+
+    /** Starts a shortcut and a task to a split pair in one transition. */
+    void startShortcutAndTask(ShortcutInfo shortcutInfo, @Nullable Bundle options1,
+            int taskId, @Nullable Bundle options2, @SplitPosition int splitPosition,
+            float splitRatio, @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
+        final WindowContainerTransaction wct = new WindowContainerTransaction();
+        setSideStagePosition(splitPosition, wct);
+        options1 = options1 != null ? options1 : new Bundle();
+        addActivityOptions(options1, mSideStage);
+        wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
+
+        startWithTask(wct, taskId, options2, splitRatio, remoteTransition, instanceId);
+    }
+
+    /**
+     * Starts with the second task to a split pair in one transition.
+     *
+     * @param wct transaction to start the first task
+     * @param instanceId if {@code null}, will not log. Otherwise it will be used in
+     *      {@link SplitscreenEventLogger#logEnter(float, int, int, int, int, boolean)}
+     */
+    private void startWithTask(WindowContainerTransaction wct, int mainTaskId,
+            @Nullable Bundle mainOptions, float splitRatio,
+            @Nullable RemoteTransition remoteTransition, InstanceId instanceId) {
         if (mMainStage.isActive()) {
             mMainStage.evictAllChildren(wct);
             mSideStage.evictAllChildren(wct);
@@ -538,60 +579,61 @@
         wct.setForceTranslucent(mRootTaskInfo.token, false);
 
         // Make sure the launch options will put tasks in the corresponding split roots
+        mainOptions = mainOptions != null ? mainOptions : new Bundle();
         addActivityOptions(mainOptions, mMainStage);
-        addActivityOptions(sideOptions, mSideStage);
 
         // Add task launch requests
         wct.startTask(mainTaskId, mainOptions);
-        wct.startTask(sideTaskId, sideOptions);
 
         mSplitTransitions.startEnterTransition(
                 TRANSIT_SPLIT_SCREEN_PAIR_OPEN, wct, remoteTransition, this, null);
         setEnterInstanceId(instanceId);
     }
 
-    /** Starts 2 tasks in one legacy transition. */
-    void startTasksWithLegacyTransition(int mainTaskId, @Nullable Bundle mainOptions,
-            int sideTaskId, @Nullable Bundle sideOptions, @SplitPosition int sidePosition,
+    /** Starts a pair of tasks using legacy transition. */
+    void startTasksWithLegacyTransition(int taskId1, @Nullable Bundle options1,
+            int taskId2, @Nullable Bundle options2, @SplitPosition int splitPosition,
             float splitRatio, RemoteAnimationAdapter adapter,
             InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        if (sideOptions == null) sideOptions = new Bundle();
-        addActivityOptions(sideOptions, mSideStage);
-        wct.startTask(sideTaskId, sideOptions);
+        if (options1 == null) options1 = new Bundle();
+        addActivityOptions(options1, mSideStage);
+        wct.startTask(taskId1, options1);
 
-        startWithLegacyTransition(wct, mainTaskId, mainOptions, sidePosition, splitRatio, adapter,
+        startWithLegacyTransition(wct, taskId2, options2, splitPosition, splitRatio, adapter,
                 instanceId);
     }
 
-    /** Start an intent and a task ordered by {@code intentFirst}. */
+    /** Starts a pair of intent and task using legacy transition. */
     void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
-            int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
-            @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+            @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
+            @SplitPosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
             InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        if (sideOptions == null) sideOptions = new Bundle();
-        addActivityOptions(sideOptions, mSideStage);
-        wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
+        if (options1 == null) options1 = new Bundle();
+        addActivityOptions(options1, mSideStage);
+        wct.sendPendingIntent(pendingIntent, fillInIntent, options1);
 
-        startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter,
+        startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter,
                 instanceId);
     }
 
+    /** Starts a pair of shortcut and task using legacy transition. */
     void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo,
-            int taskId, @Nullable Bundle mainOptions, @Nullable Bundle sideOptions,
-            @SplitPosition int sidePosition, float splitRatio, RemoteAnimationAdapter adapter,
+            @Nullable Bundle options1, int taskId, @Nullable Bundle options2,
+            @SplitPosition int splitPosition, float splitRatio, RemoteAnimationAdapter adapter,
             InstanceId instanceId) {
         final WindowContainerTransaction wct = new WindowContainerTransaction();
-        if (sideOptions == null) sideOptions = new Bundle();
-        addActivityOptions(sideOptions, mSideStage);
-        wct.startShortcut(mContext.getPackageName(), shortcutInfo, sideOptions);
+        if (options1 == null) options1 = new Bundle();
+        addActivityOptions(options1, mSideStage);
+        wct.startShortcut(mContext.getPackageName(), shortcutInfo, options1);
 
-        startWithLegacyTransition(wct, taskId, mainOptions, sidePosition, splitRatio, adapter,
+        startWithLegacyTransition(wct, taskId, options2, splitPosition, splitRatio, adapter,
                 instanceId);
     }
 
     /**
+     * @param wct transaction to start the first task
      * @param instanceId if {@code null}, will not log. Otherwise it will be used in
      *                   {@link SplitscreenEventLogger#logEnter(float, int, int, int, int, boolean)}
      */
@@ -1727,6 +1769,7 @@
 
     @StageType
     private int getStageType(StageTaskListener stage) {
+        if (stage == null) return STAGE_TYPE_UNDEFINED;
         return stage == mMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
     }
 
@@ -1981,8 +2024,8 @@
             }
         }
 
-        // TODO: fallback logic. Probably start a new transition to exit split before applying
-        //       anything here. Ideally consolidate with transition-merging.
+        // TODO(b/250853925): fallback logic. Probably start a new transition to exit split before
+        //       applying anything here. Ideally consolidate with transition-merging.
         if (info.getType() == TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE) {
             if (mainChild == null && sideChild == null) {
                 throw new IllegalStateException("Launched a task in split, but didn't receive any"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index 014f02b..8bba4404 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -15,38 +15,20 @@
  */
 package com.android.wm.shell.startingsurface;
 
-import static android.view.Choreographer.CALLBACK_COMMIT;
 import static android.view.View.GONE;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM;
 
 import android.animation.Animator;
-import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.BlendMode;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.RadialGradient;
 import android.graphics.Rect;
-import android.graphics.Shader;
-import android.util.MathUtils;
 import android.util.Slog;
-import android.view.Choreographer;
 import android.view.SurfaceControl;
-import android.view.SyncRtSurfaceTransactionApplier;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
 import android.window.SplashScreenView;
 
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.wm.shell.R;
-import com.android.wm.shell.animation.Interpolators;
 import com.android.wm.shell.common.TransactionPool;
 
 /**
@@ -55,14 +37,8 @@
  */
 public class SplashScreenExitAnimation implements Animator.AnimatorListener {
     private static final boolean DEBUG_EXIT_ANIMATION = false;
-    private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
     private static final String TAG = StartingWindowController.TAG;
 
-    private static final Interpolator ICON_INTERPOLATOR = new PathInterpolator(0.15f, 0f, 1f, 1f);
-    private static final Interpolator MASK_RADIUS_INTERPOLATOR =
-            new PathInterpolator(0f, 0f, 0.4f, 1f);
-    private static final Interpolator SHIFT_UP_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);
-
     private final SurfaceControl mFirstWindowSurface;
     private final Rect mFirstWindowFrame = new Rect();
     private final SplashScreenView mSplashScreenView;
@@ -75,9 +51,6 @@
     private final float mBrandingStartAlpha;
     private final TransactionPool mTransactionPool;
 
-    private ValueAnimator mMainAnimator;
-    private ShiftUpAnimation mShiftUpAnimation;
-    private RadialVanishAnimation mRadialVanishAnimation;
     private Runnable mFinishCallback;
 
     SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash,
@@ -121,187 +94,10 @@
     }
 
     void startAnimations() {
-        mMainAnimator = createAnimator();
-        mMainAnimator.start();
-    }
-
-    // fade out icon, reveal app, shift up main window
-    private ValueAnimator createAnimator() {
-        // reveal app
-        final float transparentRatio = 0.8f;
-        final int globalHeight = mSplashScreenView.getHeight();
-        final int verticalCircleCenter = 0;
-        final int finalVerticalLength = globalHeight - verticalCircleCenter;
-        final int halfWidth = mSplashScreenView.getWidth() / 2;
-        final int endRadius = (int) (0.5 + (1f / transparentRatio * (int)
-                Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth)));
-        final int[] colors = {Color.WHITE, Color.WHITE, Color.TRANSPARENT};
-        final float[] stops = {0f, transparentRatio, 1f};
-
-        mRadialVanishAnimation = new RadialVanishAnimation(mSplashScreenView);
-        mRadialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter);
-        mRadialVanishAnimation.setRadius(0 /* initRadius */, endRadius);
-        mRadialVanishAnimation.setRadialPaintParam(colors, stops);
-
-        if (mFirstWindowSurface != null && mFirstWindowSurface.isValid()) {
-            // shift up main window
-            View occludeHoleView = new View(mSplashScreenView.getContext());
-            if (DEBUG_EXIT_ANIMATION_BLEND) {
-                occludeHoleView.setBackgroundColor(Color.BLUE);
-            } else {
-                occludeHoleView.setBackgroundColor(mSplashScreenView.getInitBackgroundColor());
-            }
-            final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
-                    WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
-            mSplashScreenView.addView(occludeHoleView, params);
-
-            mShiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength, occludeHoleView);
-        }
-
-        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
-        animator.setDuration(mAnimationDuration);
-        animator.setInterpolator(Interpolators.LINEAR);
-        animator.addListener(this);
-        animator.addUpdateListener(a -> onAnimationProgress((float) a.getAnimatedValue()));
-        return animator;
-    }
-
-    private static class RadialVanishAnimation extends View {
-        private final SplashScreenView mView;
-        private int mInitRadius;
-        private int mFinishRadius;
-
-        private final Point mCircleCenter = new Point();
-        private final Matrix mVanishMatrix = new Matrix();
-        private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
-        RadialVanishAnimation(SplashScreenView target) {
-            super(target.getContext());
-            mView = target;
-            mView.addView(this);
-            mVanishPaint.setAlpha(0);
-        }
-
-        void onAnimationProgress(float linearProgress) {
-            if (mVanishPaint.getShader() == null) {
-                return;
-            }
-
-            final float radiusProgress = MASK_RADIUS_INTERPOLATOR.getInterpolation(linearProgress);
-            final float alphaProgress = Interpolators.ALPHA_OUT.getInterpolation(linearProgress);
-            final float scale = mInitRadius + (mFinishRadius - mInitRadius) * radiusProgress;
-
-            mVanishMatrix.setScale(scale, scale);
-            mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
-            mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
-            mVanishPaint.setAlpha(Math.round(0xFF * alphaProgress));
-
-            postInvalidate();
-        }
-
-        void setRadius(int initRadius, int finishRadius) {
-            if (DEBUG_EXIT_ANIMATION) {
-                Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius
-                        + " final " + finishRadius);
-            }
-            mInitRadius = initRadius;
-            mFinishRadius = finishRadius;
-        }
-
-        void setCircleCenter(int x, int y) {
-            if (DEBUG_EXIT_ANIMATION) {
-                Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y);
-            }
-            mCircleCenter.set(x, y);
-        }
-
-        void setRadialPaintParam(int[] colors, float[] stops) {
-            // setup gradient shader
-            final RadialGradient rShader =
-                    new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP);
-            mVanishPaint.setShader(rShader);
-            if (!DEBUG_EXIT_ANIMATION_BLEND) {
-                // We blend the reveal gradient with the splash screen using DST_OUT so that the
-                // splash screen is fully visible when radius = 0 (or gradient opacity is 0) and
-                // fully invisible when radius = finishRadius AND gradient opacity is 1.
-                mVanishPaint.setBlendMode(BlendMode.DST_OUT);
-            }
-        }
-
-        @Override
-        protected void onDraw(Canvas canvas) {
-            super.onDraw(canvas);
-            canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint);
-        }
-    }
-
-    private final class ShiftUpAnimation {
-        private final float mFromYDelta;
-        private final float mToYDelta;
-        private final View mOccludeHoleView;
-        private final SyncRtSurfaceTransactionApplier mApplier;
-        private final Matrix mTmpTransform = new Matrix();
-
-        ShiftUpAnimation(float fromYDelta, float toYDelta, View occludeHoleView) {
-            mFromYDelta = fromYDelta;
-            mToYDelta = toYDelta;
-            mOccludeHoleView = occludeHoleView;
-            mApplier = new SyncRtSurfaceTransactionApplier(occludeHoleView);
-        }
-
-        void onAnimationProgress(float linearProgress) {
-            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()
-                    || !mSplashScreenView.isAttachedToWindow()) {
-                return;
-            }
-
-            final float progress = SHIFT_UP_INTERPOLATOR.getInterpolation(linearProgress);
-            final float dy = mFromYDelta + (mToYDelta - mFromYDelta) * progress;
-
-            mOccludeHoleView.setTranslationY(dy);
-            mTmpTransform.setTranslate(0 /* dx */, dy);
-
-            // set the vsyncId to ensure the transaction doesn't get applied too early.
-            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
-            tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
-            mTmpTransform.postTranslate(mFirstWindowFrame.left,
-                    mFirstWindowFrame.top + mMainWindowShiftLength);
-
-            SyncRtSurfaceTransactionApplier.SurfaceParams
-                    params = new SyncRtSurfaceTransactionApplier.SurfaceParams
-                    .Builder(mFirstWindowSurface)
-                    .withMatrix(mTmpTransform)
-                    .withMergeTransaction(tx)
-                    .build();
-            mApplier.scheduleApply(params);
-
-            mTransactionPool.release(tx);
-        }
-
-        void finish() {
-            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) {
-                return;
-            }
-            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
-            if (mSplashScreenView.isAttachedToWindow()) {
-                tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
-
-                SyncRtSurfaceTransactionApplier.SurfaceParams
-                        params = new SyncRtSurfaceTransactionApplier.SurfaceParams
-                        .Builder(mFirstWindowSurface)
-                        .withWindowCrop(null)
-                        .withMergeTransaction(tx)
-                        .build();
-                mApplier.scheduleApply(params);
-            } else {
-                tx.setWindowCrop(mFirstWindowSurface, null);
-                tx.apply();
-            }
-            mTransactionPool.release(tx);
-
-            Choreographer.getSfInstance().postCallback(CALLBACK_COMMIT,
-                    mFirstWindowSurface::release, null);
-        }
+        SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface,
+                mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration,
+                mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay,
+                mAppRevealDuration, this);
     }
 
     private void reset() {
@@ -316,9 +112,6 @@
                 mFinishCallback = null;
             }
         }
-        if (mShiftUpAnimation != null) {
-            mShiftUpAnimation.finish();
-        }
     }
 
     @Override
@@ -342,40 +135,4 @@
     public void onAnimationRepeat(Animator animation) {
         // ignore
     }
-
-    private void onFadeOutProgress(float linearProgress) {
-        final float iconProgress = ICON_INTERPOLATOR.getInterpolation(
-                getProgress(linearProgress, 0 /* delay */, mIconFadeOutDuration));
-        final View iconView = mSplashScreenView.getIconView();
-        final View brandingView = mSplashScreenView.getBrandingView();
-        if (iconView != null) {
-            iconView.setAlpha(mIconStartAlpha * (1 - iconProgress));
-        }
-        if (brandingView != null) {
-            brandingView.setAlpha(mBrandingStartAlpha * (1 - iconProgress));
-        }
-    }
-
-    private void onAnimationProgress(float linearProgress) {
-        onFadeOutProgress(linearProgress);
-
-        final float revealLinearProgress = getProgress(linearProgress, mAppRevealDelay,
-                mAppRevealDuration);
-
-        if (mRadialVanishAnimation != null) {
-            mRadialVanishAnimation.onAnimationProgress(revealLinearProgress);
-        }
-
-        if (mShiftUpAnimation != null) {
-            mShiftUpAnimation.onAnimationProgress(revealLinearProgress);
-        }
-    }
-
-    private float getProgress(float linearProgress, long delay, long duration) {
-        return MathUtils.constrain(
-                (linearProgress * (mAnimationDuration) - delay) / duration,
-                0.0f,
-                1.0f
-        );
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
new file mode 100644
index 0000000..3098e55
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.startingsurface;
+
+import static android.view.Choreographer.CALLBACK_COMMIT;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.BlendMode;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.util.MathUtils;
+import android.util.Slog;
+import android.view.Choreographer;
+import android.view.SurfaceControl;
+import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.window.SplashScreenView;
+
+import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.TransactionPool;
+
+/**
+ * Utilities for creating the splash screen window animations.
+ * @hide
+ */
+public class SplashScreenExitAnimationUtils {
+    private static final boolean DEBUG_EXIT_ANIMATION = false;
+    private static final boolean DEBUG_EXIT_ANIMATION_BLEND = false;
+    private static final String TAG = "SplashScreenExitAnimationUtils";
+
+    private static final Interpolator ICON_INTERPOLATOR = new PathInterpolator(0.15f, 0f, 1f, 1f);
+    private static final Interpolator MASK_RADIUS_INTERPOLATOR =
+            new PathInterpolator(0f, 0f, 0.4f, 1f);
+    private static final Interpolator SHIFT_UP_INTERPOLATOR = new PathInterpolator(0f, 0f, 0f, 1f);
+
+    /**
+     * Creates and starts the animator to fade out the icon, reveal the app, and shift up main
+     * window.
+     * @hide
+     */
+    public static void startAnimations(ViewGroup splashScreenView,
+            SurfaceControl firstWindowSurface, int mainWindowShiftLength,
+            TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
+            int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
+            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener) {
+        ValueAnimator animator =
+                createAnimator(splashScreenView, firstWindowSurface, mainWindowShiftLength,
+                        transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration,
+                        iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration,
+                        animatorListener);
+        animator.start();
+    }
+
+    /**
+     * Creates the animator to fade out the icon, reveal the app, and shift up main window.
+     * @hide
+     */
+    private static ValueAnimator createAnimator(ViewGroup splashScreenView,
+            SurfaceControl firstWindowSurface, int mMainWindowShiftLength,
+            TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
+            int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
+            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener) {
+        // reveal app
+        final float transparentRatio = 0.8f;
+        final int globalHeight = splashScreenView.getHeight();
+        final int verticalCircleCenter = 0;
+        final int finalVerticalLength = globalHeight - verticalCircleCenter;
+        final int halfWidth = splashScreenView.getWidth() / 2;
+        final int endRadius = (int) (0.5 + (1f / transparentRatio * (int)
+                Math.sqrt(finalVerticalLength * finalVerticalLength + halfWidth * halfWidth)));
+        final int[] colors = {Color.WHITE, Color.WHITE, Color.TRANSPARENT};
+        final float[] stops = {0f, transparentRatio, 1f};
+
+        RadialVanishAnimation radialVanishAnimation = new RadialVanishAnimation(splashScreenView);
+        radialVanishAnimation.setCircleCenter(halfWidth, verticalCircleCenter);
+        radialVanishAnimation.setRadius(0 /* initRadius */, endRadius);
+        radialVanishAnimation.setRadialPaintParam(colors, stops);
+
+        View occludeHoleView = null;
+        ShiftUpAnimation shiftUpAnimation = null;
+        if (firstWindowSurface != null && firstWindowSurface.isValid()) {
+            // shift up main window
+            occludeHoleView = new View(splashScreenView.getContext());
+            if (DEBUG_EXIT_ANIMATION_BLEND) {
+                occludeHoleView.setBackgroundColor(Color.BLUE);
+            } else if (splashScreenView instanceof SplashScreenView) {
+                occludeHoleView.setBackgroundColor(
+                        ((SplashScreenView) splashScreenView).getInitBackgroundColor());
+            } else {
+                occludeHoleView.setBackgroundColor(
+                        isDarkTheme(splashScreenView.getContext()) ? Color.BLACK : Color.WHITE);
+            }
+            final ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
+                    WindowManager.LayoutParams.MATCH_PARENT, mMainWindowShiftLength);
+            splashScreenView.addView(occludeHoleView, params);
+
+            shiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength, occludeHoleView,
+                    firstWindowSurface, splashScreenView, transactionPool, firstWindowFrame,
+                    mMainWindowShiftLength);
+        }
+
+        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+        animator.setDuration(animationDuration);
+        animator.setInterpolator(Interpolators.LINEAR);
+        if (animatorListener != null) {
+            animator.addListener(animatorListener);
+        }
+        View finalOccludeHoleView = occludeHoleView;
+        ShiftUpAnimation finalShiftUpAnimation = shiftUpAnimation;
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                if (finalShiftUpAnimation != null) {
+                    finalShiftUpAnimation.finish();
+                }
+                splashScreenView.removeView(radialVanishAnimation);
+                splashScreenView.removeView(finalOccludeHoleView);
+            }
+        });
+        animator.addUpdateListener(animation -> {
+            float linearProgress = (float) animation.getAnimatedValue();
+
+            // Fade out progress
+            final float iconProgress =
+                    ICON_INTERPOLATOR.getInterpolation(getProgress(
+                            linearProgress, 0 /* delay */, iconFadeOutDuration, animationDuration));
+            View iconView = null;
+            View brandingView = null;
+            if (splashScreenView instanceof SplashScreenView) {
+                iconView = ((SplashScreenView) splashScreenView).getIconView();
+                brandingView = ((SplashScreenView) splashScreenView).getBrandingView();
+            }
+            if (iconView != null) {
+                iconView.setAlpha(iconStartAlpha * (1 - iconProgress));
+            }
+            if (brandingView != null) {
+                brandingView.setAlpha(brandingStartAlpha * (1 - iconProgress));
+            }
+
+            final float revealLinearProgress = getProgress(linearProgress, appRevealDelay,
+                    appRevealDuration, animationDuration);
+
+            radialVanishAnimation.onAnimationProgress(revealLinearProgress);
+
+            if (finalShiftUpAnimation != null) {
+                finalShiftUpAnimation.onAnimationProgress(revealLinearProgress);
+            }
+        });
+        return animator;
+    }
+
+    private static float getProgress(float linearProgress, long delay, long duration,
+                                     int animationDuration) {
+        return MathUtils.constrain(
+                (linearProgress * (animationDuration) - delay) / duration,
+                0.0f,
+                1.0f
+        );
+    }
+
+    private static boolean isDarkTheme(Context context) {
+        Configuration configuration = context.getResources().getConfiguration();
+        int nightMode = configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK;
+        return nightMode == Configuration.UI_MODE_NIGHT_YES;
+    }
+
+    /**
+     * View which creates a circular reveal of the underlying view.
+     * @hide
+     */
+    @SuppressLint("ViewConstructor")
+    public static class RadialVanishAnimation extends View {
+        private final ViewGroup mView;
+        private int mInitRadius;
+        private int mFinishRadius;
+
+        private final Point mCircleCenter = new Point();
+        private final Matrix mVanishMatrix = new Matrix();
+        private final Paint mVanishPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+        public RadialVanishAnimation(ViewGroup target) {
+            super(target.getContext());
+            mView = target;
+            mView.addView(this);
+            if (getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
+                ((ViewGroup.MarginLayoutParams) getLayoutParams()).setMargins(0, 0, 0, 0);
+            }
+            mVanishPaint.setAlpha(0);
+        }
+
+        void onAnimationProgress(float linearProgress) {
+            if (mVanishPaint.getShader() == null) {
+                return;
+            }
+
+            final float radiusProgress = MASK_RADIUS_INTERPOLATOR.getInterpolation(linearProgress);
+            final float alphaProgress = Interpolators.ALPHA_OUT.getInterpolation(linearProgress);
+            final float scale = mInitRadius + (mFinishRadius - mInitRadius) * radiusProgress;
+
+            mVanishMatrix.setScale(scale, scale);
+            mVanishMatrix.postTranslate(mCircleCenter.x, mCircleCenter.y);
+            mVanishPaint.getShader().setLocalMatrix(mVanishMatrix);
+            mVanishPaint.setAlpha(Math.round(0xFF * alphaProgress));
+
+            postInvalidate();
+        }
+
+        void setRadius(int initRadius, int finishRadius) {
+            if (DEBUG_EXIT_ANIMATION) {
+                Slog.v(TAG, "RadialVanishAnimation setRadius init: " + initRadius
+                        + " final " + finishRadius);
+            }
+            mInitRadius = initRadius;
+            mFinishRadius = finishRadius;
+        }
+
+        void setCircleCenter(int x, int y) {
+            if (DEBUG_EXIT_ANIMATION) {
+                Slog.v(TAG, "RadialVanishAnimation setCircleCenter x: " + x + " y " + y);
+            }
+            mCircleCenter.set(x, y);
+        }
+
+        void setRadialPaintParam(int[] colors, float[] stops) {
+            // setup gradient shader
+            final RadialGradient rShader =
+                    new RadialGradient(0, 0, 1, colors, stops, Shader.TileMode.CLAMP);
+            mVanishPaint.setShader(rShader);
+            if (!DEBUG_EXIT_ANIMATION_BLEND) {
+                // We blend the reveal gradient with the splash screen using DST_OUT so that the
+                // splash screen is fully visible when radius = 0 (or gradient opacity is 0) and
+                // fully invisible when radius = finishRadius AND gradient opacity is 1.
+                mVanishPaint.setBlendMode(BlendMode.DST_OUT);
+            }
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRect(0, 0, mView.getWidth(), mView.getHeight(), mVanishPaint);
+        }
+    }
+
+    /**
+     * Shifts up the main window.
+     * @hide
+     */
+    public static final class ShiftUpAnimation {
+        private final float mFromYDelta;
+        private final float mToYDelta;
+        private final View mOccludeHoleView;
+        private final SyncRtSurfaceTransactionApplier mApplier;
+        private final Matrix mTmpTransform = new Matrix();
+        private final SurfaceControl mFirstWindowSurface;
+        private final ViewGroup mSplashScreenView;
+        private final TransactionPool mTransactionPool;
+        private final Rect mFirstWindowFrame;
+        private final int mMainWindowShiftLength;
+
+        public ShiftUpAnimation(float fromYDelta, float toYDelta, View occludeHoleView,
+                                SurfaceControl firstWindowSurface, ViewGroup splashScreenView,
+                                TransactionPool transactionPool, Rect firstWindowFrame,
+                                int mainWindowShiftLength) {
+            mFromYDelta = fromYDelta;
+            mToYDelta = toYDelta;
+            mOccludeHoleView = occludeHoleView;
+            mApplier = new SyncRtSurfaceTransactionApplier(occludeHoleView);
+            mFirstWindowSurface = firstWindowSurface;
+            mSplashScreenView = splashScreenView;
+            mTransactionPool = transactionPool;
+            mFirstWindowFrame = firstWindowFrame;
+            mMainWindowShiftLength = mainWindowShiftLength;
+        }
+
+        void onAnimationProgress(float linearProgress) {
+            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()
+                    || !mSplashScreenView.isAttachedToWindow()) {
+                return;
+            }
+
+            final float progress = SHIFT_UP_INTERPOLATOR.getInterpolation(linearProgress);
+            final float dy = mFromYDelta + (mToYDelta - mFromYDelta) * progress;
+
+            mOccludeHoleView.setTranslationY(dy);
+            mTmpTransform.setTranslate(0 /* dx */, dy);
+
+            // set the vsyncId to ensure the transaction doesn't get applied too early.
+            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+            tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+            mTmpTransform.postTranslate(mFirstWindowFrame.left,
+                    mFirstWindowFrame.top + mMainWindowShiftLength);
+
+            SyncRtSurfaceTransactionApplier.SurfaceParams
+                    params = new SyncRtSurfaceTransactionApplier.SurfaceParams
+                    .Builder(mFirstWindowSurface)
+                    .withMatrix(mTmpTransform)
+                    .withMergeTransaction(tx)
+                    .build();
+            mApplier.scheduleApply(params);
+
+            mTransactionPool.release(tx);
+        }
+
+        void finish() {
+            if (mFirstWindowSurface == null || !mFirstWindowSurface.isValid()) {
+                return;
+            }
+            final SurfaceControl.Transaction tx = mTransactionPool.acquire();
+            if (mSplashScreenView.isAttachedToWindow()) {
+                tx.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
+
+                SyncRtSurfaceTransactionApplier.SurfaceParams
+                        params = new SyncRtSurfaceTransactionApplier.SurfaceParams
+                        .Builder(mFirstWindowSurface)
+                        .withWindowCrop(null)
+                        .withMergeTransaction(tx)
+                        .build();
+                mApplier.scheduleApply(params);
+            } else {
+                tx.setWindowCrop(mFirstWindowSurface, null);
+                tx.apply();
+            }
+            mTransactionPool.release(tx);
+
+            Choreographer.getSfInstance().postCallback(CALLBACK_COMMIT,
+                    mFirstWindowSurface::release, null);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index 76105a3..538bbec 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -22,14 +22,6 @@
  * Interface to engage starting window feature.
  */
 public interface StartingSurface {
-
-    /**
-     * Returns a binder that can be passed to an external process to manipulate starting windows.
-     */
-    default IStartingWindow createExternalInterface() {
-        return null;
-    }
-
     /**
      * Returns the background color for a starting window if existing.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index 379af21..0c23f10 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -23,6 +23,7 @@
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
 
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.TaskInfo;
@@ -43,10 +44,12 @@
 import com.android.internal.util.function.TriConsumer;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SingleInstanceRemoteListener;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 
 /**
@@ -76,6 +79,7 @@
     private TriConsumer<Integer, Integer, Integer> mTaskLaunchingCallback;
     private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
     private final Context mContext;
+    private final ShellController mShellController;
     private final ShellTaskOrganizer mShellTaskOrganizer;
     private final ShellExecutor mSplashScreenExecutor;
     /**
@@ -86,12 +90,14 @@
 
     public StartingWindowController(Context context,
             ShellInit shellInit,
+            ShellController shellController,
             ShellTaskOrganizer shellTaskOrganizer,
             ShellExecutor splashScreenExecutor,
             StartingWindowTypeAlgorithm startingWindowTypeAlgorithm,
             IconProvider iconProvider,
             TransactionPool pool) {
         mContext = context;
+        mShellController = shellController;
         mShellTaskOrganizer = shellTaskOrganizer;
         mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
                 iconProvider, pool);
@@ -107,8 +113,14 @@
         return mImpl;
     }
 
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IStartingWindowImpl(this);
+    }
+
     private void onInit() {
         mShellTaskOrganizer.initStartingWindow(this);
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_STARTING_WINDOW,
+                this::createExternalInterface, this);
     }
 
     @Override
@@ -222,17 +234,6 @@
      * The interface for calls from outside the Shell, within the host process.
      */
     private class StartingSurfaceImpl implements StartingSurface {
-        private IStartingWindowImpl mIStartingWindow;
-
-        @Override
-        public IStartingWindowImpl createExternalInterface() {
-            if (mIStartingWindow != null) {
-                mIStartingWindow.invalidate();
-            }
-            mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this);
-            return mIStartingWindow;
-        }
-
         @Override
         public int getBackgroundColor(TaskInfo taskInfo) {
             synchronized (mTaskBackgroundColors) {
@@ -256,7 +257,8 @@
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class IStartingWindowImpl extends IStartingWindow.Stub {
+    private static class IStartingWindowImpl extends IStartingWindow.Stub
+            implements ExternalInterfaceBinder {
         private StartingWindowController mController;
         private SingleInstanceRemoteListener<StartingWindowController,
                 IStartingWindowListener> mListener;
@@ -276,7 +278,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mController = null;
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
index 5799394..fdf073f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
@@ -23,23 +23,28 @@
 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
 
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_INIT;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SYSUI_EVENTS;
 
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
+import android.os.Bundle;
+import android.util.ArrayMap;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.annotations.ExternalThread;
 
 import java.io.PrintWriter;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
 
 /**
  * Handles event callbacks from SysUI that can be used within the Shell.
@@ -59,6 +64,11 @@
     private final CopyOnWriteArrayList<UserChangeListener> mUserChangeListeners =
             new CopyOnWriteArrayList<>();
 
+    private ArrayMap<String, Supplier<ExternalInterfaceBinder>> mExternalInterfaceSuppliers =
+            new ArrayMap<>();
+    // References to the existing interfaces, to be invalidated when they are recreated
+    private ArrayMap<String, ExternalInterfaceBinder> mExternalInterfaces = new ArrayMap<>();
+
     private Configuration mLastConfiguration;
 
 
@@ -67,6 +77,11 @@
         mShellInit = shellInit;
         mShellCommandHandler = shellCommandHandler;
         mMainExecutor = mainExecutor;
+        shellInit.addInitCallback(this::onInit, this);
+    }
+
+    private void onInit() {
+        mShellCommandHandler.addDumpCallback(this::dump, this);
     }
 
     /**
@@ -124,6 +139,47 @@
         mUserChangeListeners.remove(listener);
     }
 
+    /**
+     * Adds an interface that can be called from a remote process. This method takes a supplier
+     * because each binder reference is valid for a single process, and in multi-user mode, SysUI
+     * will request new binder instances for each instance of Launcher that it provides binders
+     * to.
+     *
+     * @param extra the key for the interface, {@see ShellSharedConstants}
+     * @param binderSupplier the supplier of the binder to pass to the external process
+     * @param callerInstance the instance of the caller, purely for logging
+     */
+    public void addExternalInterface(String extra, Supplier<ExternalInterfaceBinder> binderSupplier,
+            Object callerInstance) {
+        ProtoLog.v(WM_SHELL_INIT, "Adding external interface from %s with key %s",
+                callerInstance.getClass().getSimpleName(), extra);
+        if (mExternalInterfaceSuppliers.containsKey(extra)) {
+            throw new IllegalArgumentException("Supplier with same key already exists: "
+                    + extra);
+        }
+        mExternalInterfaceSuppliers.put(extra, binderSupplier);
+    }
+
+    /**
+     * Updates the given bundle with the set of external interfaces, invalidating the old set of
+     * binders.
+     */
+    private void createExternalInterfaces(Bundle output) {
+        // Invalidate the old binders
+        for (int i = 0; i < mExternalInterfaces.size(); i++) {
+            mExternalInterfaces.valueAt(i).invalidate();
+        }
+        mExternalInterfaces.clear();
+
+        // Create new binders for each key
+        for (int i = 0; i < mExternalInterfaceSuppliers.size(); i++) {
+            final String key = mExternalInterfaceSuppliers.keyAt(i);
+            final ExternalInterfaceBinder b = mExternalInterfaceSuppliers.valueAt(i).get();
+            mExternalInterfaces.put(key, b);
+            output.putBinder(key, b.asBinder());
+        }
+    }
+
     @VisibleForTesting
     void onConfigurationChanged(Configuration newConfig) {
         // The initial config is send on startup and doesn't trigger listener callbacks
@@ -204,6 +260,14 @@
         pw.println(innerPrefix + "mLastConfiguration=" + mLastConfiguration);
         pw.println(innerPrefix + "mKeyguardChangeListeners=" + mKeyguardChangeListeners.size());
         pw.println(innerPrefix + "mUserChangeListeners=" + mUserChangeListeners.size());
+
+        if (!mExternalInterfaces.isEmpty()) {
+            pw.println(innerPrefix + "mExternalInterfaces={");
+            for (String key : mExternalInterfaces.keySet()) {
+                pw.println(innerPrefix + "\t" + key + ": " + mExternalInterfaces.get(key));
+            }
+            pw.println(innerPrefix + "}");
+        }
     }
 
     /**
@@ -211,7 +275,6 @@
      */
     @ExternalThread
     private class ShellInterfaceImpl implements ShellInterface {
-
         @Override
         public void onInit() {
             try {
@@ -222,28 +285,6 @@
         }
 
         @Override
-        public void dump(PrintWriter pw) {
-            try {
-                mMainExecutor.executeBlocking(() -> mShellCommandHandler.dump(pw));
-            } catch (InterruptedException e) {
-                throw new RuntimeException("Failed to dump the Shell in 2s", e);
-            }
-        }
-
-        @Override
-        public boolean handleCommand(String[] args, PrintWriter pw) {
-            try {
-                boolean[] result = new boolean[1];
-                mMainExecutor.executeBlocking(() -> {
-                    result[0] = mShellCommandHandler.handleCommand(args, pw);
-                });
-                return result[0];
-            } catch (InterruptedException e) {
-                throw new RuntimeException("Failed to handle Shell command in 2s", e);
-            }
-        }
-
-        @Override
         public void onConfigurationChanged(Configuration newConfiguration) {
             mMainExecutor.execute(() ->
                     ShellController.this.onConfigurationChanged(newConfiguration));
@@ -274,5 +315,38 @@
             mMainExecutor.execute(() ->
                     ShellController.this.onUserProfilesChanged(profiles));
         }
+
+        @Override
+        public boolean handleCommand(String[] args, PrintWriter pw) {
+            try {
+                boolean[] result = new boolean[1];
+                mMainExecutor.executeBlocking(() -> {
+                    result[0] = mShellCommandHandler.handleCommand(args, pw);
+                });
+                return result[0];
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Failed to handle Shell command in 2s", e);
+            }
+        }
+
+        @Override
+        public void createExternalInterfaces(Bundle bundle) {
+            try {
+                mMainExecutor.executeBlocking(() -> {
+                    ShellController.this.createExternalInterfaces(bundle);
+                });
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Failed to get Shell command in 2s", e);
+            }
+        }
+
+        @Override
+        public void dump(PrintWriter pw) {
+            try {
+                mMainExecutor.executeBlocking(() -> mShellCommandHandler.dump(pw));
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Failed to dump the Shell in 2s", e);
+            }
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java
index 2108c82..bc5dd11 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
+import android.os.Bundle;
 
 import androidx.annotation.NonNull;
 
@@ -37,18 +38,6 @@
     default void onInit() {}
 
     /**
-     * Dumps the shell state.
-     */
-    default void dump(PrintWriter pw) {}
-
-    /**
-     * Handles a shell command.
-     */
-    default boolean handleCommand(final String[] args, PrintWriter pw) {
-        return false;
-    }
-
-    /**
      * Notifies the Shell that the configuration has changed.
      */
     default void onConfigurationChanged(Configuration newConfiguration) {}
@@ -74,4 +63,21 @@
      * Notifies the Shell when a profile belonging to the user changes.
      */
     default void onUserProfilesChanged(@NonNull List<UserInfo> profiles) {}
+
+    /**
+     * Handles a shell command.
+     */
+    default boolean handleCommand(final String[] args, PrintWriter pw) {
+        return false;
+    }
+
+    /**
+     * Updates the given {@param bundle} with the set of exposed interfaces.
+     */
+    default void createExternalInterfaces(Bundle bundle) {}
+
+    /**
+     * Dumps the shell state.
+     */
+    default void dump(PrintWriter pw) {}
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
new file mode 100644
index 0000000..bdda6a8
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellSharedConstants.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.sysui;
+
+/**
+ * General shell-related constants that are shared with users of the library.
+ */
+public class ShellSharedConstants {
+    // See IPip.aidl
+    public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
+    // See ISplitScreen.aidl
+    public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
+    // See IOneHanded.aidl
+    public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
+    // See IShellTransitions.aidl
+    public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
+            "extra_shell_shell_transitions";
+    // See IStartingWindow.aidl
+    public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
+            "extra_shell_starting_window";
+    // See IRecentTasks.aidl
+    public static final String KEY_EXTRA_SHELL_RECENT_TASKS = "extra_shell_recent_tasks";
+    // See IBackAnimation.aidl
+    public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation";
+    // See IFloatingTasks.aidl
+    public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
+    // See IDesktopMode.aidl
+    public static final String KEY_EXTRA_SHELL_DESKTOP_MODE = "extra_shell_desktop_mode";
+}
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 4c927b6..dbb2948 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
@@ -18,13 +18,11 @@
 
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
 import static android.app.ActivityOptions.ANIM_CUSTOM;
-import static android.app.ActivityOptions.ANIM_FROM_STYLE;
 import static android.app.ActivityOptions.ANIM_NONE;
 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
 import static android.app.ActivityOptions.ANIM_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
 import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -43,10 +41,11 @@
 import static android.view.WindowManager.TRANSIT_RELAUNCH;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.transitTypeToString;
 import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
 import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
 import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+import static android.window.TransitionInfo.FLAG_FILLS_TASK;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -59,6 +58,10 @@
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -74,7 +77,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
@@ -84,7 +86,6 @@
 import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.view.Choreographer;
@@ -122,21 +123,6 @@
 public class DefaultTransitionHandler implements Transitions.TransitionHandler {
     private static final int MAX_ANIMATION_DURATION = 3000;
 
-    /**
-     * Restrict ability of activities overriding transition animation in a way such that
-     * an activity can do it only when the transition happens within a same task.
-     *
-     * @see android.app.Activity#overridePendingTransition(int, int)
-     */
-    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
-            "persist.wm.disable_custom_task_animation";
-
-    /**
-     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
-     */
-    static boolean sDisableCustomTaskAnimationProperty =
-            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
-
     private final TransactionPool mTransactionPool;
     private final DisplayController mDisplayController;
     private final Context mContext;
@@ -384,8 +370,10 @@
                         change.getEndAbsBounds().top - info.getRootOffset().y);
                 // Seamless display transition doesn't need to animate.
                 if (isSeamlessDisplayChange) continue;
-                if (isTask) {
-                    // Skip non-tasks since those usually have null bounds.
+                if (isTask || (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)
+                        && !change.hasFlags(FLAG_FILLS_TASK))) {
+                    // Update Task and embedded split window crop bounds, otherwise we may see crop
+                    // on previous bounds during the rotation animation.
                     startTransaction.setWindowCrop(change.getLeash(),
                             change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
                 }
@@ -431,22 +419,8 @@
                     cornerRadius = 0;
                 }
 
-                if (a.getShowBackdrop()) {
-                    if (info.getAnimationOptions().getBackgroundColor() != 0) {
-                        // If available use the background color provided through AnimationOptions
-                        backgroundColorForTransition =
-                                info.getAnimationOptions().getBackgroundColor();
-                    } else if (a.getBackdropColor() != 0) {
-                        // Otherwise fallback on the background color provided through the animation
-                        // definition.
-                        backgroundColorForTransition = a.getBackdropColor();
-                    } else if (change.getBackgroundColor() != 0) {
-                        // Otherwise default to the window's background color if provided through
-                        // the theme as the background color for the animation - the top most window
-                        // with a valid background color and showBackground set takes precedence.
-                        backgroundColorForTransition = change.getBackgroundColor();
-                    }
-                }
+                backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a,
+                        backgroundColorForTransition);
 
                 boolean delayedEdgeExtension = false;
                 if (!isTask && a.hasExtension()) {
@@ -668,29 +642,6 @@
         return edgeExtensionLayer;
     }
 
-    private void addBackgroundToTransition(
-            @NonNull SurfaceControl rootLeash,
-            @ColorInt int color,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction
-    ) {
-        final Color bgColor = Color.valueOf(color);
-        final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
-
-        final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
-                .setName("Animation Background")
-                .setParent(rootLeash)
-                .setColorLayer()
-                .setOpaque(true)
-                .build();
-
-        startTransaction
-                .setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
-                .setColor(animationBackgroundSurface, colorArray)
-                .show(animationBackgroundSurface);
-        finishTransaction.remove(animationBackgroundSurface);
-    }
-
     @Nullable
     @Override
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -704,9 +655,9 @@
     }
 
     @Nullable
-    private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change,
-            int wallpaperTransit) {
-        Animation a = null;
+    private Animation loadAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, int wallpaperTransit) {
+        Animation a;
 
         final int type = info.getType();
         final int flags = info.getFlags();
@@ -717,12 +668,10 @@
         final boolean isTask = change.getTaskInfo() != null;
         final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
         final int overrideType = options != null ? options.getType() : ANIM_NONE;
-        final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true;
+        final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
         final Rect endBounds = Transitions.isClosingType(changeMode)
                 ? mRotator.getEndBoundsInStartRotation(change)
                 : change.getEndAbsBounds();
-        final boolean isDream =
-                isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
 
         if (info.isKeyguardGoingAway()) {
             a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
@@ -763,87 +712,7 @@
             // This received a transferred starting window, so don't animate
             return null;
         } else {
-            int animAttr = 0;
-            boolean translucent = false;
-            if (isDream) {
-                if (type == TRANSIT_OPEN) {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
-                            : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
-                } else if (type == TRANSIT_CLOSE) {
-                    animAttr = enter
-                            ? 0
-                            : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
-                }
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
-            } else if (type == TRANSIT_OPEN) {
-                // We will translucent open animation for translucent activities and tasks. Choose
-                // WindowAnimation_activityOpenEnterAnimation and set translucent here, then
-                // TransitionAnimation loads appropriate animation later.
-                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
-                    translucent = true;
-                }
-                if (isTask && !translucent) {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_taskOpenEnterAnimation
-                            : R.styleable.WindowAnimation_taskOpenExitAnimation;
-                } else {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_activityOpenEnterAnimation
-                            : R.styleable.WindowAnimation_activityOpenExitAnimation;
-                }
-            } else if (type == TRANSIT_TO_FRONT) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
-                        : R.styleable.WindowAnimation_taskToFrontExitAnimation;
-            } else if (type == TRANSIT_CLOSE) {
-                if (isTask) {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_taskCloseEnterAnimation
-                            : R.styleable.WindowAnimation_taskCloseExitAnimation;
-                } else {
-                    if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
-                        translucent = true;
-                    }
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_activityCloseEnterAnimation
-                            : R.styleable.WindowAnimation_activityCloseExitAnimation;
-                }
-            } else if (type == TRANSIT_TO_BACK) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_taskToBackEnterAnimation
-                        : R.styleable.WindowAnimation_taskToBackExitAnimation;
-            }
-
-            if (animAttr != 0) {
-                if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
-                    a = mTransitionAnimation
-                            .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
-                                    animAttr, translucent);
-                } else {
-                    a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
-                }
-            }
-
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                    "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
-                    transitTypeToString(type),
-                    enter);
+            a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation);
         }
 
         if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
index b34049d..da39017 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
@@ -27,14 +27,6 @@
  */
 @ExternalThread
 public interface ShellTransitions {
-
-    /**
-     * Returns a binder that can be passed to an external process to manipulate remote transitions.
-     */
-    default IShellTransitions createExternalInterface() {
-        return null;
-    }
-
     /**
      * Registers a remote transition.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
new file mode 100644
index 0000000..efee6f40
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -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.wm.shell.transition;
+
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
+import static android.app.ActivityOptions.ANIM_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
+
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Color;
+import android.os.SystemProperties;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.window.TransitionInfo;
+
+import com.android.internal.R;
+import com.android.internal.policy.TransitionAnimation;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+/** The helper class that provides methods for adding styles to transition animations. */
+public class TransitionAnimationHelper {
+
+    /**
+     * Restrict ability of activities overriding transition animation in a way such that
+     * an activity can do it only when the transition happens within a same task.
+     *
+     * @see android.app.Activity#overridePendingTransition(int, int)
+     */
+    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
+            "persist.wm.disable_custom_task_animation";
+
+    /**
+     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
+     */
+    static final boolean sDisableCustomTaskAnimationProperty =
+            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
+
+    /** Loads the animation that is defined through attribute id for the given transition. */
+    @Nullable
+    public static Animation loadAttributeAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, int wallpaperTransit,
+            @NonNull TransitionAnimation transitionAnimation) {
+        final int type = info.getType();
+        final int changeMode = change.getMode();
+        final int changeFlags = change.getFlags();
+        final boolean enter = Transitions.isOpeningType(changeMode);
+        final boolean isTask = change.getTaskInfo() != null;
+        final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
+        final int overrideType = options != null ? options.getType() : ANIM_NONE;
+        final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
+        final boolean isDream =
+                isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
+        int animAttr = 0;
+        boolean translucent = false;
+        if (isDream) {
+            if (type == TRANSIT_OPEN) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
+                        : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
+            } else if (type == TRANSIT_CLOSE) {
+                animAttr = enter
+                        ? 0
+                        : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
+            }
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
+        } else if (type == TRANSIT_OPEN) {
+            // We will translucent open animation for translucent activities and tasks. Choose
+            // WindowAnimation_activityOpenEnterAnimation and set translucent here, then
+            // TransitionAnimation loads appropriate animation later.
+            if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
+                translucent = true;
+            }
+            if (isTask && !translucent) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_taskOpenEnterAnimation
+                        : R.styleable.WindowAnimation_taskOpenExitAnimation;
+            } else {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_activityOpenEnterAnimation
+                        : R.styleable.WindowAnimation_activityOpenExitAnimation;
+            }
+        } else if (type == TRANSIT_TO_FRONT) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
+                    : R.styleable.WindowAnimation_taskToFrontExitAnimation;
+        } else if (type == TRANSIT_CLOSE) {
+            if (isTask) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_taskCloseEnterAnimation
+                        : R.styleable.WindowAnimation_taskCloseExitAnimation;
+            } else {
+                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
+                    translucent = true;
+                }
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_activityCloseEnterAnimation
+                        : R.styleable.WindowAnimation_activityCloseExitAnimation;
+            }
+        } else if (type == TRANSIT_TO_BACK) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_taskToBackEnterAnimation
+                    : R.styleable.WindowAnimation_taskToBackExitAnimation;
+        }
+
+        Animation a = null;
+        if (animAttr != 0) {
+            if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
+                a = transitionAnimation
+                        .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
+                                animAttr, translucent);
+            } else {
+                a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
+            }
+        }
+
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
+                transitTypeToString(type),
+                enter);
+        return a;
+    }
+
+    /**
+     * Gets the background {@link ColorInt} for the given transition animation if it is set.
+     *
+     * @param defaultColor  {@link ColorInt} to return if there is no background color specified by
+     *                      the given transition animation.
+     */
+    @ColorInt
+    public static int getTransitionBackgroundColorIfSet(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, @NonNull Animation a,
+            @ColorInt int defaultColor) {
+        if (!a.getShowBackdrop()) {
+            return defaultColor;
+        }
+        if (info.getAnimationOptions() != null
+                && info.getAnimationOptions().getBackgroundColor() != 0) {
+            // If available use the background color provided through AnimationOptions
+            return info.getAnimationOptions().getBackgroundColor();
+        } else if (a.getBackdropColor() != 0) {
+            // Otherwise fallback on the background color provided through the animation
+            // definition.
+            return a.getBackdropColor();
+        } else if (change.getBackgroundColor() != 0) {
+            // Otherwise default to the window's background color if provided through
+            // the theme as the background color for the animation - the top most window
+            // with a valid background color and showBackground set takes precedence.
+            return change.getBackgroundColor();
+        }
+        return defaultColor;
+    }
+
+    /**
+     * Adds the given {@code backgroundColor} as the background color to the transition animation.
+     */
+    public static void addBackgroundToTransition(@NonNull SurfaceControl rootLeash,
+            @ColorInt int backgroundColor, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        if (backgroundColor == 0) {
+            // No background color.
+            return;
+        }
+        final Color bgColor = Color.valueOf(backgroundColor);
+        final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
+        final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
+                .setName("Animation Background")
+                .setParent(rootLeash)
+                .setColorLayer()
+                .setOpaque(true)
+                .build();
+        startTransaction
+                .setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
+                .setColor(animationBackgroundSurface, colorArray)
+                .show(animationBackgroundSurface);
+        finishTransaction.remove(animationBackgroundSurface);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 29d25bc..d1bc738 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -25,10 +25,12 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.fixScale;
 import static android.window.TransitionInfo.FLAG_IS_INPUT_METHOD;
+import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 
 import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
+import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -61,11 +63,13 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 
 import java.util.ArrayList;
@@ -115,6 +119,7 @@
     private final DefaultTransitionHandler mDefaultTransitionHandler;
     private final RemoteTransitionHandler mRemoteTransitionHandler;
     private final DisplayController mDisplayController;
+    private final ShellController mShellController;
     private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
 
     /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
@@ -142,6 +147,7 @@
 
     public Transitions(@NonNull Context context,
             @NonNull ShellInit shellInit,
+            @NonNull ShellController shellController,
             @NonNull WindowOrganizer organizer,
             @NonNull TransactionPool pool,
             @NonNull DisplayController displayController,
@@ -156,10 +162,14 @@
         mDefaultTransitionHandler = new DefaultTransitionHandler(context, shellInit,
                 displayController, pool, mainExecutor, mainHandler, animExecutor);
         mRemoteTransitionHandler = new RemoteTransitionHandler(mMainExecutor);
+        mShellController = shellController;
         shellInit.addInitCallback(this::onInit, this);
     }
 
     private void onInit() {
+        mShellController.addExternalInterface(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
+                this::createExternalInterface, this);
+
         // The very last handler (0 in the list) should be the default one.
         mHandlers.add(mDefaultTransitionHandler);
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "addHandler: Default");
@@ -193,6 +203,10 @@
         return mImpl;
     }
 
+    private ExternalInterfaceBinder createExternalInterface() {
+        return new IShellTransitionsImpl(this);
+    }
+
     @Override
     public Context getContext() {
         return mContext;
@@ -441,31 +455,34 @@
             return;
         }
 
-        // apply transfer starting window directly if there is no other task change. Since this
-        // is an activity->activity situation, we can detect it by selecting transitions with only
-        // 2 changes where neither are tasks and one is a starting-window recipient.
         final int changeSize = info.getChanges().size();
-        if (changeSize == 2) {
-            boolean nonTaskChange = true;
-            boolean transferStartingWindow = false;
-            for (int i = changeSize - 1; i >= 0; --i) {
-                final TransitionInfo.Change change = info.getChanges().get(i);
-                if (change.getTaskInfo() != null) {
-                    nonTaskChange = false;
-                    break;
-                }
-                if ((change.getFlags() & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
-                    transferStartingWindow = true;
-                }
+        boolean taskChange = false;
+        boolean transferStartingWindow = false;
+        boolean allOccluded = changeSize > 0;
+        for (int i = changeSize - 1; i >= 0; --i) {
+            final TransitionInfo.Change change = info.getChanges().get(i);
+            taskChange |= change.getTaskInfo() != null;
+            transferStartingWindow |= change.hasFlags(FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT);
+            if (!change.hasFlags(FLAG_IS_OCCLUDED)) {
+                allOccluded = false;
             }
-            if (nonTaskChange && transferStartingWindow) {
-                t.apply();
-                finishT.apply();
-                // Treat this as an abort since we are bypassing any merge logic and effectively
-                // finishing immediately.
-                onAbort(transitionToken);
-                return;
-            }
+        }
+        // There does not need animation when:
+        // A. Transfer starting window. Apply transfer starting window directly if there is no other
+        // task change. Since this is an activity->activity situation, we can detect it by selecting
+        // transitions with only 2 changes where neither are tasks and one is a starting-window
+        // recipient.
+        if (!taskChange && transferStartingWindow && changeSize == 2
+                // B. It's visibility change if the TRANSIT_TO_BACK/TO_FRONT happened when all
+                // changes are underneath another change.
+                || ((info.getType() == TRANSIT_TO_BACK || info.getType() == TRANSIT_TO_FRONT)
+                && allOccluded)) {
+            t.apply();
+            finishT.apply();
+            // Treat this as an abort since we are bypassing any merge logic and effectively
+            // finishing immediately.
+            onAbort(transitionToken);
+            return;
         }
 
         final ActiveTransition active = mActiveTransitions.get(activeIdx);
@@ -542,6 +559,22 @@
                 "This shouldn't happen, maybe the default handler is broken.");
     }
 
+    /**
+     * Gives every handler (in order) a chance to handle request until one consumes the transition.
+     * @return the WindowContainerTransaction given by the handler which consumed the transition.
+     */
+    public WindowContainerTransaction dispatchRequest(@NonNull IBinder transition,
+            @NonNull TransitionRequestInfo request, @Nullable TransitionHandler skip) {
+        for (int i = mHandlers.size() - 1; i >= 0; --i) {
+            if (mHandlers.get(i) == skip) continue;
+            WindowContainerTransaction wct = mHandlers.get(i).handleRequest(transition, request);
+            if (wct != null) {
+                return wct;
+            }
+        }
+        return null;
+    }
+
     /** Special version of finish just for dealing with no-op/invalid transitions. */
     private void onAbort(IBinder transition) {
         onFinish(transition, null /* wct */, null /* wctCB */, true /* abort */);
@@ -716,8 +749,8 @@
                         null /* newDisplayAreaInfo */);
             }
         }
-        active.mToken = mOrganizer.startTransition(
-                request.getType(), transitionToken, wct);
+        mOrganizer.startTransition(transitionToken, wct != null && wct.isEmpty() ? null : wct);
+        active.mToken = transitionToken;
         mActiveTransitions.add(active);
     }
 
@@ -726,7 +759,7 @@
             @NonNull WindowContainerTransaction wct, @Nullable TransitionHandler handler) {
         final ActiveTransition active = new ActiveTransition();
         active.mHandler = handler;
-        active.mToken = mOrganizer.startTransition(type, null /* token */, wct);
+        active.mToken = mOrganizer.startNewTransition(type, wct);
         mActiveTransitions.add(active);
         return active.mToken;
     }
@@ -897,17 +930,6 @@
      */
     @ExternalThread
     private class ShellTransitionImpl implements ShellTransitions {
-        private IShellTransitionsImpl mIShellTransitions;
-
-        @Override
-        public IShellTransitions createExternalInterface() {
-            if (mIShellTransitions != null) {
-                mIShellTransitions.invalidate();
-            }
-            mIShellTransitions = new IShellTransitionsImpl(Transitions.this);
-            return mIShellTransitions;
-        }
-
         @Override
         public void registerRemote(@NonNull TransitionFilter filter,
                 @NonNull RemoteTransition remoteTransition) {
@@ -928,7 +950,8 @@
      * The interface for calls from outside the host process.
      */
     @BinderThread
-    private static class IShellTransitionsImpl extends IShellTransitions.Stub {
+    private static class IShellTransitionsImpl extends IShellTransitions.Stub
+            implements ExternalInterfaceBinder {
         private Transitions mTransitions;
 
         IShellTransitionsImpl(Transitions transitions) {
@@ -938,7 +961,8 @@
         /**
          * Invalidates this instance, preventing future calls from updating the controller.
          */
-        void invalidate() {
+        @Override
+        public void invalidate() {
             mTransitions = null;
         }
 
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 e8a2cb160..dca516a 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
@@ -16,16 +16,23 @@
 
 package com.android.wm.shell.windowdecor;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityTaskManager;
 import android.content.Context;
+import android.hardware.input.InputManager;
 import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.SparseArray;
 import android.view.Choreographer;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.View;
@@ -36,7 +43,8 @@
 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.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeController;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
 import com.android.wm.shell.transition.Transitions;
 
@@ -44,7 +52,9 @@
  * View model for the window decoration with a caption and shadows. Works with
  * {@link CaptionWindowDecoration}.
  */
-public class CaptionWindowDecorViewModel implements WindowDecorViewModel<CaptionWindowDecoration> {
+
+public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
+    private static final String TAG = "CaptionViewModel";
     private final ActivityTaskManager mActivityTaskManager;
     private final ShellTaskOrganizer mTaskOrganizer;
     private final Context mContext;
@@ -53,6 +63,9 @@
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
     private FreeformTaskTransitionStarter mTransitionStarter;
+    private DesktopModeController mDesktopModeController;
+
+    private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
 
     public CaptionWindowDecorViewModel(
             Context context,
@@ -60,7 +73,8 @@
             Choreographer mainChoreographer,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue,
+            DesktopModeController desktopModeController) {
         mContext = context;
         mMainHandler = mainHandler;
         mMainChoreographer = mainChoreographer;
@@ -68,6 +82,7 @@
         mTaskOrganizer = taskOrganizer;
         mDisplayController = displayController;
         mSyncQueue = syncQueue;
+        mDesktopModeController = desktopModeController;
     }
 
     @Override
@@ -76,12 +91,12 @@
     }
 
     @Override
-    public CaptionWindowDecoration createWindowDecoration(
+    public boolean createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        if (!shouldShowWindowDecor(taskInfo)) return null;
+        if (!shouldShowWindowDecor(taskInfo)) return false;
         final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
                 mContext,
                 mDisplayController,
@@ -91,47 +106,45 @@
                 mMainHandler,
                 mMainChoreographer,
                 mSyncQueue);
+        mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
+
         TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration);
         CaptionTouchEventListener touchEventListener =
                 new CaptionTouchEventListener(taskInfo, taskPositioner);
         windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
         windowDecoration.setDragResizeCallback(taskPositioner);
-        setupWindowDecorationForTransition(taskInfo, startT, finishT, windowDecoration);
-        setupCaptionColor(taskInfo, windowDecoration);
-        return windowDecoration;
+        setupWindowDecorationForTransition(taskInfo, startT, finishT);
+        return true;
     }
 
     @Override
-    public CaptionWindowDecoration adoptWindowDecoration(AutoCloseable windowDecor) {
-        if (!(windowDecor instanceof CaptionWindowDecoration)) return null;
-        final CaptionWindowDecoration captionWindowDecor = (CaptionWindowDecoration) windowDecor;
-        if (!shouldShowWindowDecor(captionWindowDecor.mTaskInfo)) {
-            return null;
-        }
-        return captionWindowDecor;
-    }
+    public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
+        final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
+        if (decoration == null) return;
 
-    @Override
-    public void onTaskInfoChanged(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
         decoration.relayout(taskInfo);
-
-        setupCaptionColor(taskInfo, decoration);
-    }
-
-    private void setupCaptionColor(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
-        int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
-        decoration.setCaptionColor(statusBarColor);
     }
 
     @Override
     public void setupWindowDecorationForTransition(
             RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT,
-            CaptionWindowDecoration decoration) {
+            SurfaceControl.Transaction finishT) {
+        final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
+        if (decoration == null) return;
+
         decoration.relayout(taskInfo, startT, finishT);
     }
 
+    @Override
+    public void destroyWindowDecoration(RunningTaskInfo taskInfo) {
+        final CaptionWindowDecoration decoration =
+                mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
+        if (decoration == null) return;
+
+        decoration.close();
+    }
+
     private class CaptionTouchEventListener implements
             View.OnClickListener, View.OnTouchListener {
 
@@ -140,6 +153,7 @@
         private final DragResizeCallback mDragResizeCallback;
 
         private int mDragPointerId = -1;
+        private boolean mDragActive = false;
 
         private CaptionTouchEventListener(
                 RunningTaskInfo taskInfo,
@@ -160,42 +174,38 @@
                 } else {
                     mSyncQueue.queue(wct);
                 }
-            } else if (id == R.id.maximize_window) {
-                WindowContainerTransaction wct = new WindowContainerTransaction();
-                RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-                int targetWindowingMode = taskInfo.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
-                        ? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_FREEFORM;
-                int displayWindowingMode =
-                        taskInfo.configuration.windowConfiguration.getDisplayWindowingMode();
-                wct.setWindowingMode(mTaskToken,
-                        targetWindowingMode == displayWindowingMode
-                            ? WINDOWING_MODE_UNDEFINED : targetWindowingMode);
-                if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) {
-                    wct.setBounds(mTaskToken, null);
-                }
-                if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-                    mTransitionStarter.startWindowingModeTransition(targetWindowingMode, wct);
-                } else {
-                    mSyncQueue.queue(wct);
-                }
-            } else if (id == R.id.minimize_window) {
-                WindowContainerTransaction wct = new WindowContainerTransaction();
-                wct.reorder(mTaskToken, false);
-                if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-                    mTransitionStarter.startMinimizedModeTransition(wct);
-                } else {
-                    mSyncQueue.queue(wct);
-                }
+            } else if (id == R.id.back_button) {
+                injectBackKey();
+            }
+        }
+        private void injectBackKey() {
+            sendBackEvent(KeyEvent.ACTION_DOWN);
+            sendBackEvent(KeyEvent.ACTION_UP);
+        }
+
+        private void sendBackEvent(int action) {
+            final long when = SystemClock.uptimeMillis();
+            final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK,
+                    0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD,
+                    0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+                    InputDevice.SOURCE_KEYBOARD);
+
+            ev.setDisplayId(mContext.getDisplay().getDisplayId());
+            if (!InputManager.getInstance()
+                    .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
+                Log.e(TAG, "Inject input event fail");
             }
         }
 
         @Override
         public boolean onTouch(View v, MotionEvent e) {
-            if (v.getId() != R.id.caption) {
+            int id = v.getId();
+            if (id != R.id.caption_handle && id != R.id.caption) {
                 return false;
             }
-            handleEventForMove(e);
-
+            if (id == R.id.caption_handle || mDragActive) {
+                handleEventForMove(e);
+            }
             if (e.getAction() != MotionEvent.ACTION_DOWN) {
                 return false;
             }
@@ -210,12 +220,15 @@
         }
 
         private void handleEventForMove(MotionEvent e) {
-            if (mTaskOrganizer.getRunningTaskInfo(mTaskId).getWindowingMode()
-                    == WINDOWING_MODE_FULLSCREEN) {
+            RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+            int windowingMode =  mDesktopModeController
+                    .getDisplayAreaWindowingMode(taskInfo.displayId);
+            if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
                 return;
             }
             switch (e.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
+                    mDragActive = true;
                     mDragPointerId  = e.getPointerId(0);
                     mDragResizeCallback.onDragResizeStart(
                             0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
@@ -228,9 +241,16 @@
                 }
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL: {
+                    mDragActive = false;
                     int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+                    int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
+                            .stableInsets().top;
                     mDragResizeCallback.onDragResizeEnd(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
+                    if (e.getRawY(dragPointerIdx) <= statusBarHeight
+                            && windowingMode == WINDOWING_MODE_FREEFORM) {
+                        mDesktopModeController.setDesktopModeActive(false);
+                    }
                     break;
                 }
             }
@@ -239,7 +259,8 @@
 
     private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
         if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
-        return DesktopMode.IS_SUPPORTED
+        return DesktopModeStatus.IS_SUPPORTED
+                && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
                 && mDisplayController.getDisplayContext(taskInfo.displayId)
                 .getResources().getConfiguration().smallestScreenWidthDp >= 600;
     }
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 5040bc3..beace75 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
@@ -22,27 +22,23 @@
 import android.content.res.ColorStateList;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.VectorDrawable;
 import android.os.Handler;
 import android.view.Choreographer;
 import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.window.WindowContainerTransaction;
 
 import com.android.wm.shell.R;
 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.DesktopMode;
+import com.android.wm.shell.desktopmode.DesktopModeStatus;
 
 /**
  * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
- * {@link CaptionWindowDecorViewModel}. The caption bar contains maximize and close buttons.
- *
- * {@link CaptionWindowDecorViewModel} can change the color of the caption bar based on the foremost
- * app's request through {@link #setCaptionColor(int)}, in which it changes the foreground color of
- * caption buttons according to the luminance of the background.
+ * {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close button.
  *
  * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't.
  */
@@ -54,7 +50,10 @@
 
     // Height of button (32dp)  + 2 * margin (5dp each)
     private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
+    // Width of buttons (64dp) + handle (128dp) + padding (24dp total)
+    private static final int DECOR_CAPTION_WIDTH_IN_DIP = 216;
     private static final int RESIZE_HANDLE_IN_DIP = 30;
+    private static final int RESIZE_CORNER_IN_DIP = 44;
 
     private static final Rect EMPTY_OUTSET = new Rect();
     private static final Rect RESIZE_HANDLE_OUTSET = new Rect(
@@ -73,6 +72,8 @@
     private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
             new WindowDecoration.RelayoutResult<>();
 
+    private boolean mDesktopActive;
+
     CaptionWindowDecoration(
             Context context,
             DisplayController displayController,
@@ -87,6 +88,7 @@
         mHandler = handler;
         mChoreographer = choreographer;
         mSyncQueue = syncQueue;
+        mDesktopActive = DesktopModeStatus.isActive(mContext);
     }
 
     void setCaptionListeners(
@@ -123,8 +125,8 @@
         final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
         final WindowContainerTransaction wct = new WindowContainerTransaction();
         relayout(taskInfo, R.layout.caption_window_decoration, oldRootView,
-                DECOR_CAPTION_HEIGHT_IN_DIP, outset, shadowRadiusDp, startT, finishT, wct, mResult);
-        taskInfo = null; // Clear it just in case we use it accidentally
+                DECOR_CAPTION_HEIGHT_IN_DIP, DECOR_CAPTION_WIDTH_IN_DIP, outset, shadowRadiusDp,
+                startT, finishT, wct, mResult);
 
         mTaskOrganizer.applyTransaction(wct);
 
@@ -137,6 +139,17 @@
             setupRootView();
         }
 
+        // If this task is not focused, do not show caption.
+        setCaptionVisibility(taskInfo.isFocused);
+
+        // Only handle should show if Desktop Mode is inactive.
+        boolean desktopCurrentStatus = DesktopModeStatus.isActive(mContext);
+        if (mDesktopActive != desktopCurrentStatus && taskInfo.isFocused) {
+            mDesktopActive = desktopCurrentStatus;
+            setButtonVisibility();
+        }
+        taskInfo = null; // Clear it just in case we use it accidentally
+
         if (!isDragResizeable) {
             closeDragResizeListener();
             return;
@@ -145,16 +158,19 @@
         if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) {
             closeDragResizeListener();
             mDragResizeListener = new DragResizeInputListener(
-                    mContext,
-                    mHandler,
-                    mChoreographer,
-                    mDisplay.getDisplayId(),
-                    mDecorationContainerSurface,
-                    mDragResizeCallback);
+                        mContext,
+                        mHandler,
+                        mChoreographer,
+                        mDisplay.getDisplayId(),
+                        mDecorationContainerSurface,
+                        mDragResizeCallback);
         }
 
+        int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop();
+
         mDragResizeListener.setGeometry(
-                mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP));
+                mResult.mWidth, mResult.mHeight, (int) (mResult.mDensity * RESIZE_HANDLE_IN_DIP),
+                (int) (mResult.mDensity * RESIZE_CORNER_IN_DIP), touchSlop);
     }
 
     /**
@@ -163,42 +179,46 @@
     private void setupRootView() {
         View caption = mResult.mRootView.findViewById(R.id.caption);
         caption.setOnTouchListener(mOnCaptionTouchListener);
-        View maximize = caption.findViewById(R.id.maximize_window);
-        if (DesktopMode.IS_SUPPORTED) {
-            // Hide maximize button when desktop mode is available
-            maximize.setVisibility(View.GONE);
-        } else {
-            maximize.setVisibility(View.VISIBLE);
-            maximize.setOnClickListener(mOnCaptionButtonClickListener);
-        }
         View close = caption.findViewById(R.id.close_window);
         close.setOnClickListener(mOnCaptionButtonClickListener);
-        View minimize = caption.findViewById(R.id.minimize_window);
-        minimize.setOnClickListener(mOnCaptionButtonClickListener);
+        View back = caption.findViewById(R.id.back_button);
+        back.setOnClickListener(mOnCaptionButtonClickListener);
+        View handle = caption.findViewById(R.id.caption_handle);
+        handle.setOnTouchListener(mOnCaptionTouchListener);
+        setButtonVisibility();
     }
 
-    void setCaptionColor(int captionColor) {
-        if (mResult.mRootView == null) {
-            return;
-        }
-
+    /**
+     * Sets caption visibility based on task focus.
+     *
+     * @param visible whether or not the caption should be visible
+     */
+    private void setCaptionVisibility(boolean visible) {
+        int v = visible ? View.VISIBLE : View.GONE;
         View caption = mResult.mRootView.findViewById(R.id.caption);
-        GradientDrawable captionDrawable = (GradientDrawable) caption.getBackground();
-        captionDrawable.setColor(captionColor);
+        caption.setVisibility(v);
+    }
 
+    /**
+     * Sets the visibility of buttons and color of caption based on desktop mode status
+     *
+     */
+    public void setButtonVisibility() {
+        int v = mDesktopActive ? View.VISIBLE : View.GONE;
+        View caption = mResult.mRootView.findViewById(R.id.caption);
+        View back = caption.findViewById(R.id.back_button);
+        View close = caption.findViewById(R.id.close_window);
+        back.setVisibility(v);
+        close.setVisibility(v);
         int buttonTintColorRes =
-                Color.valueOf(captionColor).luminance() < 0.5
-                        ? R.color.decor_button_light_color
-                        : R.color.decor_button_dark_color;
+                mDesktopActive ? R.color.decor_button_dark_color
+                        : R.color.decor_button_light_color;
         ColorStateList buttonTintColor =
                 caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */);
-        View maximize = caption.findViewById(R.id.maximize_window);
-        VectorDrawable maximizeBackground = (VectorDrawable) maximize.getBackground();
-        maximizeBackground.setTintList(buttonTintColor);
-
-        View close = caption.findViewById(R.id.close_window);
-        VectorDrawable closeBackground = (VectorDrawable) close.getBackground();
-        closeBackground.setTintList(buttonTintColor);
+        View handle = caption.findViewById(R.id.caption_handle);
+        VectorDrawable handleBackground = (VectorDrawable) handle.getBackground();
+        handleBackground.setTintList(buttonTintColor);
+        caption.setBackgroundColor(v == View.VISIBLE ? Color.WHITE : Color.TRANSPARENT);
     }
 
     private void closeDragResizeListener() {
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 3d01495..b9f16b6 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
@@ -16,11 +16,13 @@
 
 package com.android.wm.shell.windowdecor;
 
+import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.input.InputManager;
@@ -42,8 +44,11 @@
 
 /**
  * An input event listener registered to InputDispatcher to receive input events on task edges and
- * convert them to drag resize requests.
+ * and corners. Converts them to drag resize requests.
+ * Task edges are for resizing with a mouse.
+ * Task corners are for resizing with touch input.
  */
+// TODO(b/251270585): investigate how to pass taps in corners to the tasks
 class DragResizeInputListener implements AutoCloseable {
     private static final String TAG = "DragResizeInputListener";
 
@@ -63,8 +68,15 @@
     private int mWidth;
     private int mHeight;
     private int mResizeHandleThickness;
+    private int mCornerSize;
+
+    private Rect mLeftTopCornerBounds;
+    private Rect mRightTopCornerBounds;
+    private Rect mLeftBottomCornerBounds;
+    private Rect mRightBottomCornerBounds;
 
     private int mDragPointerId = -1;
+    private int mTouchSlop;
 
     DragResizeInputListener(
             Context context,
@@ -118,16 +130,23 @@
      * @param height The height of the drag resize handler in pixels, including resize handle
      *               thickness. That is task height + 2 * resize handle thickness.
      * @param resizeHandleThickness The thickness of the resize handle in pixels.
+     * @param cornerSize The size of the resize handle centered in each corner.
+     * @param touchSlop The distance in pixels user has to drag with touch for it to register as
+     *                  a resize action.
      */
-    void setGeometry(int width, int height, int resizeHandleThickness) {
+    void setGeometry(int width, int height, int resizeHandleThickness, int cornerSize,
+            int touchSlop) {
         if (mWidth == width && mHeight == height
-                && mResizeHandleThickness == resizeHandleThickness) {
+                && mResizeHandleThickness == resizeHandleThickness
+                && mCornerSize == cornerSize) {
             return;
         }
 
         mWidth = width;
         mHeight = height;
         mResizeHandleThickness = resizeHandleThickness;
+        mCornerSize = cornerSize;
+        mTouchSlop = touchSlop;
 
         Region touchRegion = new Region();
         final Rect topInputBounds = new Rect(0, 0, mWidth, mResizeHandleThickness);
@@ -146,6 +165,40 @@
                 mWidth, mHeight);
         touchRegion.union(bottomInputBounds);
 
+        // Set up touch areas in each corner.
+        int cornerRadius = mCornerSize / 2;
+        mLeftTopCornerBounds = new Rect(
+                mResizeHandleThickness - cornerRadius,
+                mResizeHandleThickness - cornerRadius,
+                mResizeHandleThickness + cornerRadius,
+                mResizeHandleThickness + cornerRadius
+        );
+        touchRegion.union(mLeftTopCornerBounds);
+
+        mRightTopCornerBounds = new Rect(
+                mWidth - mResizeHandleThickness - cornerRadius,
+                mResizeHandleThickness - cornerRadius,
+                mWidth - mResizeHandleThickness + cornerRadius,
+                mResizeHandleThickness + cornerRadius
+        );
+        touchRegion.union(mRightTopCornerBounds);
+
+        mLeftBottomCornerBounds = new Rect(
+                mResizeHandleThickness - cornerRadius,
+                mHeight - mResizeHandleThickness - cornerRadius,
+                mResizeHandleThickness + cornerRadius,
+                mHeight - mResizeHandleThickness + cornerRadius
+        );
+        touchRegion.union(mLeftBottomCornerBounds);
+
+        mRightBottomCornerBounds = new Rect(
+                mWidth - mResizeHandleThickness - cornerRadius,
+                mHeight - mResizeHandleThickness - cornerRadius,
+                mWidth - mResizeHandleThickness + cornerRadius,
+                mHeight - mResizeHandleThickness + cornerRadius
+        );
+        touchRegion.union(mRightBottomCornerBounds);
+
         try {
             mWindowSession.updateInputChannel(
                     mInputChannel.getToken(),
@@ -173,6 +226,9 @@
         private final Choreographer mChoreographer;
         private final Runnable mConsumeBatchEventRunnable;
         private boolean mConsumeBatchEventScheduled;
+        private boolean mShouldHandleEvents;
+        private boolean mDragging;
+        private final PointF mActionDownPoint = new PointF();
 
         private TaskResizeInputEventReceiver(
                 InputChannel inputChannel, Handler handler, Choreographer choreographer) {
@@ -216,41 +272,101 @@
             }
 
             MotionEvent e = (MotionEvent) inputEvent;
+            boolean result = false;
+            // Check if this is a touch event vs mouse event.
+            // Touch events are tracked in four corners. Other events are tracked in resize edges.
+            boolean isTouch = (e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN;
+
             switch (e.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN: {
-                    mDragPointerId = e.getPointerId(0);
-                    mCallback.onDragResizeStart(
-                            calculateCtrlType(e.getX(0), e.getY(0)), e.getRawX(0), e.getRawY(0));
+                    float x = e.getX(0);
+                    float y = e.getY(0);
+                    if (isTouch) {
+                        mShouldHandleEvents = isInCornerBounds(x, y);
+                    } else {
+                        mShouldHandleEvents = isInResizeHandleBounds(x, y);
+                    }
+                    if (mShouldHandleEvents) {
+                        mDragPointerId = e.getPointerId(0);
+                        float rawX = e.getRawX(0);
+                        float rawY = e.getRawY(0);
+                        mActionDownPoint.set(rawX, rawY);
+                        int ctrlType = calculateCtrlType(isTouch, x, y);
+                        mCallback.onDragResizeStart(ctrlType, rawX, rawY);
+                        result = true;
+                    }
                     break;
                 }
                 case MotionEvent.ACTION_MOVE: {
+                    if (!mShouldHandleEvents) {
+                        break;
+                    }
                     int dragPointerIndex = e.findPointerIndex(mDragPointerId);
-                    mCallback.onDragResizeMove(
-                            e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
+                    float rawX = e.getRawX(dragPointerIndex);
+                    float rawY = e.getRawY(dragPointerIndex);
+                    if (isTouch) {
+                        // Check for touch slop for touch events
+                        float dx = rawX - mActionDownPoint.x;
+                        float dy = rawY - mActionDownPoint.y;
+                        if (!mDragging && Math.hypot(dx, dy) > mTouchSlop) {
+                            mDragging = true;
+                        }
+                    } else {
+                        // For all other types allow immediate dragging.
+                        mDragging = true;
+                    }
+                    if (mDragging) {
+                        mCallback.onDragResizeMove(rawX, rawY);
+                        result = true;
+                    }
                     break;
                 }
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL: {
-                    int dragPointerIndex = e.findPointerIndex(mDragPointerId);
-                    mCallback.onDragResizeEnd(
-                            e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
+                    if (mDragging) {
+                        int dragPointerIndex = e.findPointerIndex(mDragPointerId);
+                        mCallback.onDragResizeEnd(
+                                e.getRawX(dragPointerIndex), e.getRawY(dragPointerIndex));
+                    }
+                    mDragging = false;
+                    mShouldHandleEvents = false;
+                    mActionDownPoint.set(0, 0);
                     mDragPointerId = -1;
+                    result = true;
                     break;
                 }
                 case MotionEvent.ACTION_HOVER_ENTER:
                 case MotionEvent.ACTION_HOVER_MOVE: {
                     updateCursorType(e.getXCursorPosition(), e.getYCursorPosition());
+                    result = true;
                     break;
                 }
                 case MotionEvent.ACTION_HOVER_EXIT:
                     mInputManager.setPointerIconType(PointerIcon.TYPE_DEFAULT);
+                    result = true;
                     break;
             }
-            return true;
+            return result;
+        }
+
+        private boolean isInCornerBounds(float xf, float yf) {
+            return calculateCornersCtrlType(xf, yf) != 0;
+        }
+
+        private boolean isInResizeHandleBounds(float x, float y) {
+            return calculateResizeHandlesCtrlType(x, y) != 0;
         }
 
         @TaskPositioner.CtrlType
-        private int calculateCtrlType(float x, float y) {
+        private int calculateCtrlType(boolean isTouch, float x, float y) {
+            if (isTouch) {
+                return calculateCornersCtrlType(x, y);
+            }
+            return calculateResizeHandlesCtrlType(x, y);
+        }
+
+        @TaskPositioner.CtrlType
+        private int calculateResizeHandlesCtrlType(float x, float y) {
             int ctrlType = 0;
             if (x < mResizeHandleThickness) {
                 ctrlType |= TaskPositioner.CTRL_TYPE_LEFT;
@@ -267,8 +383,27 @@
             return ctrlType;
         }
 
+        @TaskPositioner.CtrlType
+        private int calculateCornersCtrlType(float x, float y) {
+            int xi = (int) x;
+            int yi = (int) y;
+            if (mLeftTopCornerBounds.contains(xi, yi)) {
+                return TaskPositioner.CTRL_TYPE_LEFT | TaskPositioner.CTRL_TYPE_TOP;
+            }
+            if (mLeftBottomCornerBounds.contains(xi, yi)) {
+                return TaskPositioner.CTRL_TYPE_LEFT | TaskPositioner.CTRL_TYPE_BOTTOM;
+            }
+            if (mRightTopCornerBounds.contains(xi, yi)) {
+                return TaskPositioner.CTRL_TYPE_RIGHT | TaskPositioner.CTRL_TYPE_TOP;
+            }
+            if (mRightBottomCornerBounds.contains(xi, yi)) {
+                return TaskPositioner.CTRL_TYPE_RIGHT | TaskPositioner.CTRL_TYPE_BOTTOM;
+            }
+            return 0;
+        }
+
         private void updateCursorType(float x, float y) {
-            @TaskPositioner.CtrlType int ctrlType = calculateCtrlType(x, y);
+            @TaskPositioner.CtrlType int ctrlType = calculateResizeHandlesCtrlType(x, y);
 
             int cursorType = PointerIcon.TYPE_DEFAULT;
             switch (ctrlType) {
@@ -292,4 +427,4 @@
             mInputManager.setPointerIconType(cursorType);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
index 280569b..27c1011 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/TaskPositioner.java
@@ -25,9 +25,10 @@
 
 class TaskPositioner implements DragResizeCallback {
 
-    @IntDef({CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
+    @IntDef({CTRL_TYPE_UNDEFINED, CTRL_TYPE_LEFT, CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, CTRL_TYPE_BOTTOM})
     @interface CtrlType {}
 
+    static final int CTRL_TYPE_UNDEFINED = 0;
     static final int CTRL_TYPE_LEFT = 1;
     static final int CTRL_TYPE_RIGHT = 2;
     static final int CTRL_TYPE_TOP = 4;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index d9697d2..d7f71c8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -19,8 +19,6 @@
 import android.app.ActivityManager;
 import android.view.SurfaceControl;
 
-import androidx.annotation.Nullable;
-
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
 
 /**
@@ -28,10 +26,8 @@
  * customize {@link WindowDecoration}. Its implementations are responsible to interpret user's
  * interactions with UI widgets in window decorations and send corresponding requests to system
  * servers.
- *
- * @param <T> The actual decoration type
  */
-public interface WindowDecorViewModel<T extends AutoCloseable> {
+public interface WindowDecorViewModel {
 
     /**
      * Sets the transition starter that starts freeform task transitions.
@@ -50,29 +46,19 @@
      * @param finishT the finish transaction to restore states after the transition
      * @return the window decoration object
      */
-    @Nullable T createWindowDecoration(
+    boolean createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT);
 
     /**
-     * Adopts the window decoration if possible.
-     * May be {@code null} if a window decor is not needed or the given one is incompatible.
-     *
-     * @param windowDecor the potential window decoration to adopt
-     * @return the window decoration if it can be adopted, or {@code null} otherwise.
-     */
-    @Nullable T adoptWindowDecoration(@Nullable AutoCloseable windowDecor);
-
-    /**
      * Notifies a task info update on the given task, with the window decoration created previously
      * for this task by {@link #createWindowDecoration}.
      *
      * @param taskInfo the new task info of the task
-     * @param windowDecoration the window decoration created for the task
      */
-    void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo, T windowDecoration);
+    void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo);
 
     /**
      * Notifies a transition is about to start about the given task to give the window decoration a
@@ -80,11 +66,16 @@
      *
      * @param startT the start transaction to be applied before the transition
      * @param finishT the finish transaction to restore states after the transition
-     * @param windowDecoration the window decoration created for the task
      */
     void setupWindowDecorationForTransition(
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT,
-            T windowDecoration);
+            SurfaceControl.Transaction finishT);
+
+    /**
+     * Destroys the window decoration of the give task.
+     *
+     * @param taskInfo the info of the task
+     */
+    void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo);
 }
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 3e3a864..bf863ea 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
@@ -143,9 +143,9 @@
     abstract void relayout(RunningTaskInfo taskInfo);
 
     void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp,
-            Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction startT,
-            SurfaceControl.Transaction finishT, WindowContainerTransaction wct,
-            RelayoutResult<T> outResult) {
+            float captionWidthDp, Rect outsetsDp, float shadowRadiusDp,
+            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
+            WindowContainerTransaction wct, RelayoutResult<T> outResult) {
         outResult.reset();
 
         final Configuration oldTaskConfig = mTaskInfo.getConfiguration();
@@ -249,8 +249,15 @@
         }
 
         final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity);
+        final int captionWidth = (int) Math.ceil(captionWidthDp * outResult.mDensity);
+
+        //Prevent caption from going offscreen if task is too high up
+        final int captionYPos = taskBounds.top <= captionHeight / 2 ? 0 : captionHeight / 2;
+
         startT.setPosition(
-                        mCaptionContainerSurface, -decorContainerOffsetX, -decorContainerOffsetY)
+                        mCaptionContainerSurface, -decorContainerOffsetX
+                                + taskBounds.width() / 2 - captionWidth / 2,
+                        -decorContainerOffsetY - captionYPos)
                 .setWindowCrop(mCaptionContainerSurface, taskBounds.width(), captionHeight)
                 .show(mCaptionContainerSurface);
 
@@ -264,7 +271,7 @@
         // Caption view
         mCaptionWindowManager.setConfiguration(taskConfig);
         final WindowManager.LayoutParams lp =
-                new WindowManager.LayoutParams(taskBounds.width(), captionHeight,
+                new WindowManager.LayoutParams(captionWidth, captionHeight,
                         WindowManager.LayoutParams.TYPE_APPLICATION,
                         WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
         lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
@@ -282,7 +289,7 @@
 
             // Caption insets
             mCaptionInsetsRect.set(taskBounds);
-            mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight;
+            mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos;
             wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES);
         } else {
             startT.hide(mCaptionContainerSurface);
@@ -388,4 +395,4 @@
             return new SurfaceControlViewHost(c, d, wmm);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
index c0720cf..3672ae3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestRunningTaskInfoBuilder.java
@@ -44,6 +44,7 @@
     private ActivityManager.TaskDescription.Builder mTaskDescriptionBuilder = null;
     private final Point mPositionInParent = new Point();
     private boolean mIsVisible = false;
+    private long mLastActiveTime;
 
     public static WindowContainerToken createMockWCToken() {
         final IWindowContainerToken itoken = mock(IWindowContainerToken.class);
@@ -52,6 +53,11 @@
         return new WindowContainerToken(itoken);
     }
 
+    public TestRunningTaskInfoBuilder setToken(WindowContainerToken token) {
+        mToken = token;
+        return this;
+    }
+
     public TestRunningTaskInfoBuilder setBounds(Rect bounds) {
         mBounds.set(bounds);
         return this;
@@ -95,6 +101,11 @@
         return this;
     }
 
+    public TestRunningTaskInfoBuilder setLastActiveTime(long lastActiveTime) {
+        mLastActiveTime = lastActiveTime;
+        return this;
+    }
+
     public ActivityManager.RunningTaskInfo build() {
         final ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
         info.taskId = sNextTaskId++;
@@ -110,6 +121,7 @@
                 mTaskDescriptionBuilder != null ? mTaskDescriptionBuilder.build() : null;
         info.positionInParent = mPositionInParent;
         info.isVisible = mIsVisible;
+        info.lastActiveTime = mLastActiveTime;
         return info;
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 90a3773..077e9ca 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -63,7 +63,9 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.sysui.ShellSharedConstants;
 
 import org.junit.Before;
 import org.junit.Ignore;
@@ -102,6 +104,9 @@
     @Mock
     private IBackNaviAnimationController mIBackNaviAnimationController;
 
+    @Mock
+    private ShellController mShellController;
+
     private BackAnimationController mController;
 
     private int mEventTime = 0;
@@ -118,7 +123,7 @@
                 ANIMATION_ENABLED);
         mTestableLooper = TestableLooper.get(this);
         mShellInit = spy(new ShellInit(mShellExecutor));
-        mController = new BackAnimationController(mShellInit,
+        mController = new BackAnimationController(mShellInit, mShellController,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction,
                 mActivityTaskManager, mContext,
                 mContentResolver);
@@ -175,6 +180,12 @@
     }
 
     @Test
+    public void instantiateController_addExternalInterface() {
+        verify(mShellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION), any(), any());
+    }
+
+    @Test
     @Ignore("b/207481538")
     public void crossActivity_screenshotAttachedAndVisible() {
         SurfaceControl screenshotSurface = new SurfaceControl();
@@ -250,7 +261,7 @@
         // Toggle the setting off
         Settings.Global.putString(mContentResolver, Settings.Global.ENABLE_BACK_ANIMATION, "0");
         ShellInit shellInit = new ShellInit(mShellExecutor);
-        mController = new BackAnimationController(shellInit,
+        mController = new BackAnimationController(shellInit, mShellController,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()), mTransaction,
                 mActivityTaskManager, mContext,
                 mContentResolver);
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 695550d..f6d6c03 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
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.common.split;
 
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -91,6 +92,14 @@
         // Verify updateConfiguration returns true if the root bounds changed.
         config.windowConfiguration.setBounds(new Rect(0, 0, 2160, 1080));
         assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
+
+        // Verify updateConfiguration returns true if the orientation changed.
+        config.orientation = ORIENTATION_LANDSCAPE;
+        assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
+
+        // Verify updateConfiguration returns true if the density changed.
+        config.densityDpi = 123;
+        assertThat(mSplitLayout.updateConfiguration(config)).isTrue();
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 6292130..2fc0914 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -51,6 +51,7 @@
 import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.compatui.letterboxedu.LetterboxEduWindowManager;
@@ -93,6 +94,7 @@
     private @Mock Lazy<Transitions> mMockTransitionsLazy;
     private @Mock CompatUIWindowManager mMockCompatLayout;
     private @Mock LetterboxEduWindowManager mMockLetterboxEduLayout;
+    private @Mock DockStateReader mDockStateReader;
 
     @Captor
     ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor;
@@ -113,7 +115,7 @@
         mShellInit = spy(new ShellInit(mMockExecutor));
         mController = new CompatUIController(mContext, mShellInit, mMockShellController,
                 mMockDisplayController, mMockDisplayInsetsController, mMockImeController,
-                mMockSyncQueue, mMockExecutor, mMockTransitionsLazy) {
+                mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader) {
             @Override
             CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo,
                     ShellTaskOrganizer.TaskListener taskListener) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
index f3a8cf4..16517c0 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManagerTest.java
@@ -54,6 +54,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.DockStateReader;
 import com.android.wm.shell.common.SyncTransactionQueue;
 import com.android.wm.shell.transition.Transitions;
 
@@ -103,6 +104,7 @@
     @Mock private SurfaceControlViewHost mViewHost;
     @Mock private Transitions mTransitions;
     @Mock private Runnable mOnDismissCallback;
+    @Mock private DockStateReader mDockStateReader;
 
     private SharedPreferences mSharedPreferences;
     @Nullable
@@ -153,6 +155,16 @@
     }
 
     @Test
+    public void testCreateLayout_eligibleAndDocked_doesNotCreateLayout() {
+        LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */
+                true, /* isDocked */ true);
+
+        assertFalse(windowManager.createLayout(/* canShow= */ true));
+
+        assertNull(windowManager.mLayout);
+    }
+
+    @Test
     public void testCreateLayout_taskBarEducationIsShowing_doesNotCreateLayout() {
         LetterboxEduWindowManager windowManager = createWindowManager(/* eligible= */
                 true, USER_ID_1, /* isTaskbarEduShowing= */ true);
@@ -382,17 +394,27 @@
         return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */ false);
     }
 
+    private LetterboxEduWindowManager createWindowManager(boolean eligible, boolean isDocked) {
+        return createWindowManager(eligible, USER_ID_1, /* isTaskbarEduShowing= */
+                false, isDocked);
+    }
+
     private LetterboxEduWindowManager createWindowManager(boolean eligible,
             int userId, boolean isTaskbarEduShowing) {
+        return createWindowManager(eligible, userId, isTaskbarEduShowing, /* isDocked */false);
+    }
+
+    private LetterboxEduWindowManager createWindowManager(boolean eligible,
+            int userId, boolean isTaskbarEduShowing, boolean isDocked) {
+        doReturn(isDocked).when(mDockStateReader).isDocked();
         LetterboxEduWindowManager windowManager = new LetterboxEduWindowManager(mContext,
                 createTaskInfo(eligible, userId), mSyncTransactionQueue, mTaskListener,
                 createDisplayLayout(), mTransitions, mOnDismissCallback,
-                mAnimationController);
+                mAnimationController, mDockStateReader);
 
         spyOn(windowManager);
         doReturn(mViewHost).when(windowManager).createSurfaceViewHost();
         doReturn(isTaskbarEduShowing).when(windowManager).isTaskbarEduShowing();
-
         return windowManager;
     }
 
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 c628f399..c850a3b 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
@@ -19,16 +19,22 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.app.WindowConfiguration;
+import android.app.ActivityManager;
 import android.os.Handler;
 import android.os.IBinder;
 import android.testing.AndroidTestingRunner;
@@ -39,13 +45,18 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -58,6 +69,8 @@
 public class DesktopModeControllerTest extends ShellTestCase {
 
     @Mock
+    private ShellController mShellController;
+    @Mock
     private ShellTaskOrganizer mShellTaskOrganizer;
     @Mock
     private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
@@ -67,18 +80,38 @@
     private Handler mMockHandler;
     @Mock
     private Transitions mMockTransitions;
+    private TestShellExecutor mExecutor;
 
     private DesktopModeController mController;
+    private DesktopModeTaskRepository mDesktopModeTaskRepository;
     private ShellInit mShellInit;
+    private StaticMockitoSession mMockitoSession;
 
     @Before
     public void setUp() {
-        mShellInit = Mockito.spy(new ShellInit(mTestExecutor));
+        mMockitoSession = mockitoSession().mockStatic(DesktopModeStatus.class).startMocking();
+        when(DesktopModeStatus.isActive(any())).thenReturn(true);
 
-        mController = new DesktopModeController(mContext, mShellInit, mShellTaskOrganizer,
-                mRootTaskDisplayAreaOrganizer, mMockHandler, mMockTransitions);
+        mShellInit = Mockito.spy(new ShellInit(mTestExecutor));
+        mExecutor = new TestShellExecutor();
+
+        mDesktopModeTaskRepository = new DesktopModeTaskRepository();
+
+        mController = new DesktopModeController(mContext, mShellInit, mShellController,
+                mShellTaskOrganizer, mRootTaskDisplayAreaOrganizer, mMockTransitions,
+                mDesktopModeTaskRepository, mMockHandler, mExecutor);
+
+        when(mShellTaskOrganizer.prepareClearFreeformForStandardTasks(anyInt())).thenReturn(
+                new WindowContainerTransaction());
 
         mShellInit.init();
+        clearInvocations(mShellTaskOrganizer);
+        clearInvocations(mRootTaskDisplayAreaOrganizer);
+    }
+
+    @After
+    public void tearDown() {
+        mMockitoSession.finishMocking();
     }
 
     @Test
@@ -159,17 +192,15 @@
         assertThat(wct.getChanges()).hasSize(3);
 
         // Verify executed WCT has a change for setting task windowing mode to undefined
-        Change taskWmModeChange = wct.getChanges().get(taskWmMockToken.binder());
-        assertThat(taskWmModeChange).isNotNull();
-        assertThat(taskWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
+        Change taskWmMode = wct.getChanges().get(taskWmMockToken.binder());
+        assertThat(taskWmMode).isNotNull();
+        assertThat(taskWmMode.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
 
         // Verify executed WCT has a change for clearing task bounds
-        Change taskBoundsChange = wct.getChanges().get(taskBoundsMockToken.binder());
-        assertThat(taskBoundsChange).isNotNull();
-        assertThat(taskBoundsChange.getWindowSetMask()
-                & WindowConfiguration.WINDOW_CONFIG_BOUNDS).isNotEqualTo(0);
-        assertThat(taskBoundsChange.getConfiguration().windowConfiguration.getBounds().isEmpty())
-                .isTrue();
+        Change bounds = wct.getChanges().get(taskBoundsMockToken.binder());
+        assertThat(bounds).isNotNull();
+        assertThat(bounds.getWindowSetMask() & WINDOW_CONFIG_BOUNDS).isNotEqualTo(0);
+        assertThat(bounds.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue();
 
         // Verify executed WCT has a change for setting display windowing mode to fullscreen
         Change displayWmModeChange = wct.getChanges().get(displayAreaInfo.token.asBinder());
@@ -177,6 +208,41 @@
         assertThat(displayWmModeChange.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN);
     }
 
+    @Test
+    public void testShowDesktopApps() {
+        // Set up two active tasks on desktop
+        mDesktopModeTaskRepository.addActiveTask(1);
+        mDesktopModeTaskRepository.addActiveTask(2);
+        MockToken token1 = new MockToken();
+        MockToken token2 = new MockToken();
+        ActivityManager.RunningTaskInfo taskInfo1 = new TestRunningTaskInfoBuilder().setToken(
+                token1.token()).setLastActiveTime(100).build();
+        ActivityManager.RunningTaskInfo taskInfo2 = new TestRunningTaskInfoBuilder().setToken(
+                token2.token()).setLastActiveTime(200).build();
+        when(mShellTaskOrganizer.getRunningTaskInfo(1)).thenReturn(taskInfo1);
+        when(mShellTaskOrganizer.getRunningTaskInfo(2)).thenReturn(taskInfo2);
+
+        // Run show desktop apps logic
+        mController.showDesktopApps();
+        ArgumentCaptor<WindowContainerTransaction> wctCaptor = ArgumentCaptor.forClass(
+                WindowContainerTransaction.class);
+        verify(mShellTaskOrganizer).applyTransaction(wctCaptor.capture());
+        WindowContainerTransaction wct = wctCaptor.getValue();
+
+        // Check wct has reorder calls
+        assertThat(wct.getHierarchyOps()).hasSize(2);
+
+        // Task 2 has activity later, must be first
+        WindowContainerTransaction.HierarchyOp op1 = wct.getHierarchyOps().get(0);
+        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
+        assertThat(op1.getContainer()).isEqualTo(token2.binder());
+
+        // Task 1 should be second
+        WindowContainerTransaction.HierarchyOp op2 = wct.getHierarchyOps().get(0);
+        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
+        assertThat(op2.getContainer()).isEqualTo(token2.binder());
+    }
+
     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/floating/FloatingTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java
index a88c837..d378a17 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java
@@ -52,6 +52,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.sysui.ShellSharedConstants;
 
 import org.junit.After;
 import org.junit.Before;
@@ -168,6 +169,18 @@
         }
     }
 
+    @Test
+    public void onInit_addExternalInterface() {
+        if (FLOATING_TASKS_ACTUALLY_ENABLED) {
+            createController();
+            setUpTabletConfig();
+            mController.onInit();
+
+            verify(mShellController, times(1)).addExternalInterface(
+                    ShellSharedConstants.KEY_EXTRA_SHELL_FLOATING_TASKS, any(), any());
+        }
+    }
+
     //
     // Tests for floating layer, which is only available for tablets.
     //
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
index 0fd5cb0..7068a84 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
@@ -17,17 +17,10 @@
 package com.android.wm.shell.freeform;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.WindowManager.TRANSIT_CHANGE;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 
-import static com.android.wm.shell.transition.Transitions.TRANSIT_MAXIMIZE;
-import static com.android.wm.shell.transition.Transitions.TRANSIT_RESTORE_FROM_MAXIMIZE;
-
-import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.same;
@@ -44,9 +37,9 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.wm.shell.fullscreen.FullscreenTaskListener;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
+import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -65,9 +58,7 @@
     @Mock
     private Transitions mTransitions;
     @Mock
-    private FullscreenTaskListener<?> mFullscreenTaskListener;
-    @Mock
-    private FreeformTaskListener<?> mFreeformTaskListener;
+    private WindowDecorViewModel mWindowDecorViewModel;
 
     private FreeformTaskTransitionObserver mTransitionObserver;
 
@@ -82,7 +73,7 @@
         doReturn(pm).when(context).getPackageManager();
 
         mTransitionObserver = new FreeformTaskTransitionObserver(
-                context, mShellInit, mTransitions, mFullscreenTaskListener, mFreeformTaskListener);
+                context, mShellInit, mTransitions, mWindowDecorViewModel);
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             final ArgumentCaptor<Runnable> initRunnableCaptor = ArgumentCaptor.forClass(
                     Runnable.class);
@@ -112,11 +103,12 @@
         mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
         mTransitionObserver.onTransitionStarting(transition);
 
-        verify(mFreeformTaskListener).createWindowDecoration(change, startT, finishT);
+        verify(mWindowDecorViewModel).createWindowDecoration(
+                change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
     @Test
-    public void testObtainsWindowDecorOnCloseTransition_freeform() {
+    public void testPreparesWindowDecorOnCloseTransition_freeform() {
         final TransitionInfo.Change change =
                 createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FREEFORM);
         final TransitionInfo info = new TransitionInfo(TRANSIT_CLOSE, 0);
@@ -128,7 +120,8 @@
         mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
         mTransitionObserver.onTransitionStarting(transition);
 
-        verify(mFreeformTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT);
+        verify(mWindowDecorViewModel).setupWindowDecorationForTransition(
+                change.getTaskInfo(), startT, finishT);
     }
 
     @Test
@@ -138,17 +131,13 @@
         final TransitionInfo info = new TransitionInfo(TRANSIT_CLOSE, 0);
         info.addChange(change);
 
-        final AutoCloseable windowDecor = mock(AutoCloseable.class);
-        doReturn(windowDecor).when(mFreeformTaskListener).giveWindowDecoration(
-                eq(change.getTaskInfo()), any(), any());
-
         final IBinder transition = mock(IBinder.class);
         final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
         final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
         mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
         mTransitionObserver.onTransitionStarting(transition);
 
-        verify(windowDecor, never()).close();
+        verify(mWindowDecorViewModel, never()).destroyWindowDecoration(change.getTaskInfo());
     }
 
     @Test
@@ -159,8 +148,6 @@
         info.addChange(change);
 
         final AutoCloseable windowDecor = mock(AutoCloseable.class);
-        doReturn(windowDecor).when(mFreeformTaskListener).giveWindowDecoration(
-                eq(change.getTaskInfo()), any(), any());
 
         final IBinder transition = mock(IBinder.class);
         final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
@@ -169,7 +156,7 @@
         mTransitionObserver.onTransitionStarting(transition);
         mTransitionObserver.onTransitionFinished(transition, false);
 
-        verify(windowDecor).close();
+        verify(mWindowDecorViewModel).destroyWindowDecoration(change.getTaskInfo());
     }
 
     @Test
@@ -192,10 +179,6 @@
         final TransitionInfo info2 = new TransitionInfo(TRANSIT_CLOSE, 0);
         info2.addChange(change2);
 
-        final AutoCloseable windowDecor2 = mock(AutoCloseable.class);
-        doReturn(windowDecor2).when(mFreeformTaskListener).giveWindowDecoration(
-                eq(change2.getTaskInfo()), any(), any());
-
         final IBinder transition2 = mock(IBinder.class);
         final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
         final SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
@@ -204,7 +187,7 @@
 
         mTransitionObserver.onTransitionFinished(transition1, false);
 
-        verify(windowDecor2).close();
+        verify(mWindowDecorViewModel).destroyWindowDecoration(change2.getTaskInfo());
     }
 
     @Test
@@ -215,10 +198,6 @@
         final TransitionInfo info1 = new TransitionInfo(TRANSIT_CLOSE, 0);
         info1.addChange(change1);
 
-        final AutoCloseable windowDecor1 = mock(AutoCloseable.class);
-        doReturn(windowDecor1).when(mFreeformTaskListener).giveWindowDecoration(
-                eq(change1.getTaskInfo()), any(), any());
-
         final IBinder transition1 = mock(IBinder.class);
         final SurfaceControl.Transaction startT1 = mock(SurfaceControl.Transaction.class);
         final SurfaceControl.Transaction finishT1 = mock(SurfaceControl.Transaction.class);
@@ -231,10 +210,6 @@
         final TransitionInfo info2 = new TransitionInfo(TRANSIT_CLOSE, 0);
         info2.addChange(change2);
 
-        final AutoCloseable windowDecor2 = mock(AutoCloseable.class);
-        doReturn(windowDecor2).when(mFreeformTaskListener).giveWindowDecoration(
-                eq(change2.getTaskInfo()), any(), any());
-
         final IBinder transition2 = mock(IBinder.class);
         final SurfaceControl.Transaction startT2 = mock(SurfaceControl.Transaction.class);
         final SurfaceControl.Transaction finishT2 = mock(SurfaceControl.Transaction.class);
@@ -243,48 +218,8 @@
 
         mTransitionObserver.onTransitionFinished(transition1, false);
 
-        verify(windowDecor1).close();
-        verify(windowDecor2).close();
-    }
-
-    @Test
-    public void testTransfersWindowDecorOnMaximize() {
-        final TransitionInfo.Change change =
-                createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN);
-        final TransitionInfo info = new TransitionInfo(TRANSIT_MAXIMIZE, 0);
-        info.addChange(change);
-
-        final AutoCloseable windowDecor = mock(AutoCloseable.class);
-        doReturn(windowDecor).when(mFreeformTaskListener).giveWindowDecoration(
-                eq(change.getTaskInfo()), any(), any());
-
-        final IBinder transition = mock(IBinder.class);
-        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
-        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
-        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
-        mTransitionObserver.onTransitionStarting(transition);
-
-        verify(mFreeformTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT);
-        verify(mFullscreenTaskListener).adoptWindowDecoration(
-                eq(change), same(startT), same(finishT), any());
-    }
-
-    @Test
-    public void testTransfersWindowDecorOnRestoreFromMaximize() {
-        final TransitionInfo.Change change =
-                createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FREEFORM);
-        final TransitionInfo info = new TransitionInfo(TRANSIT_RESTORE_FROM_MAXIMIZE, 0);
-        info.addChange(change);
-
-        final IBinder transition = mock(IBinder.class);
-        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
-        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
-        mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
-        mTransitionObserver.onTransitionStarting(transition);
-
-        verify(mFullscreenTaskListener).giveWindowDecoration(change.getTaskInfo(), startT, finishT);
-        verify(mFreeformTaskListener).adoptWindowDecoration(
-                eq(change), same(startT), same(finishT), any());
+        verify(mWindowDecorViewModel).destroyWindowDecoration(change1.getTaskInfo());
+        verify(mWindowDecorViewModel).destroyWindowDecoration(change2.getTaskInfo());
     }
 
     private static TransitionInfo.Change createChange(int mode, int taskId, int windowingMode) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
index cf8297e..8ad3d2a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java
@@ -51,6 +51,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.sysui.ShellSharedConstants;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -176,6 +177,12 @@
     }
 
     @Test
+    public void testControllerRegisteresExternalInterface() {
+        verify(mMockShellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_ONE_HANDED), any(), any());
+    }
+
+    @Test
     public void testDefaultShouldNotInOneHanded() {
         // Assert default transition state is STATE_NONE
         assertThat(mSpiedTransitionState.getState()).isEqualTo(STATE_NONE);
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 a8d3bdc..d06fb55 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
@@ -20,6 +20,7 @@
 
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -48,6 +49,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.onehanded.OneHandedController;
+import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipAppOpsListener;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -60,6 +62,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.sysui.ShellSharedConstants;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -85,6 +88,7 @@
     @Mock private ShellCommandHandler mMockShellCommandHandler;
     @Mock private DisplayController mMockDisplayController;
     @Mock private PhonePipMenuController mMockPhonePipMenuController;
+    @Mock private PipAnimationController mMockPipAnimationController;
     @Mock private PipAppOpsListener mMockPipAppOpsListener;
     @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
     @Mock private PhonePipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
@@ -117,8 +121,8 @@
         mShellController = spy(new ShellController(mShellInit, mMockShellCommandHandler,
                 mMockExecutor));
         mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
-                mShellController, mMockDisplayController, mMockPipAppOpsListener,
-                mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
+                mShellController, mMockDisplayController, mMockPipAnimationController,
+                mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
@@ -150,6 +154,12 @@
     }
 
     @Test
+    public void instantiatePipController_registerExternalInterface() {
+        verify(mShellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_PIP), any(), any());
+    }
+
+    @Test
     public void instantiatePipController_registerUserChangeListener() {
         verify(mShellController, times(1)).addUserChangeListener(any());
     }
@@ -183,8 +193,8 @@
 
         ShellInit shellInit = new ShellInit(mMockExecutor);
         assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
-                mShellController, mMockDisplayController, mMockPipAppOpsListener,
-                mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
+                mShellController, mMockDisplayController, mMockPipAnimationController,
+                mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
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 cadfeb0..f6ac3ee 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
@@ -28,6 +28,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -40,6 +41,7 @@
 import static java.lang.Integer.MAX_VALUE;
 
 import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
@@ -52,12 +54,13 @@
 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.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 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.sysui.ShellSharedConstants;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
 import com.android.wm.shell.util.SplitBounds;
 
@@ -68,7 +71,9 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Optional;
+import java.util.function.Consumer;
 
 /**
  * Tests for {@link RecentTasksController}.
@@ -82,14 +87,18 @@
     @Mock
     private TaskStackListenerImpl mTaskStackListener;
     @Mock
+    private ShellController mShellController;
+    @Mock
     private ShellCommandHandler mShellCommandHandler;
     @Mock
     private DesktopModeTaskRepository mDesktopModeTaskRepository;
+    @Mock
+    private ActivityTaskManager mActivityTaskManager;
 
     private ShellTaskOrganizer mShellTaskOrganizer;
     private RecentTasksController mRecentTasksController;
     private ShellInit mShellInit;
-    private ShellExecutor mMainExecutor;
+    private TestShellExecutor mMainExecutor;
 
     @Before
     public void setUp() {
@@ -97,8 +106,8 @@
         when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
         mShellInit = spy(new ShellInit(mMainExecutor));
         mRecentTasksController = spy(new RecentTasksController(mContext, mShellInit,
-                mShellCommandHandler, mTaskStackListener, Optional.of(mDesktopModeTaskRepository),
-                mMainExecutor));
+                mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
+                Optional.of(mDesktopModeTaskRepository), mMainExecutor));
         mShellTaskOrganizer = new ShellTaskOrganizer(mShellInit, mShellCommandHandler,
                 null /* sizeCompatUI */, Optional.empty(), Optional.of(mRecentTasksController),
                 mMainExecutor);
@@ -117,6 +126,12 @@
     }
 
     @Test
+    public void instantiateController_addExternalInterface() {
+        verify(mShellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS), any(), any());
+    }
+
+    @Test
     public void testAddRemoveSplitNotifyChange() {
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -188,10 +203,41 @@
     }
 
     @Test
+    public void testGetRecentTasks_ReturnsRecentTasksAsynchronously() {
+        @SuppressWarnings("unchecked")
+        final List<GroupedRecentTaskInfo>[] recentTasks = new List[1];
+        Consumer<List<GroupedRecentTaskInfo>> consumer = argument -> recentTasks[0] = argument;
+        ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+        ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+        ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+        ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
+        ActivityManager.RecentTaskInfo t5 = makeTaskInfo(5);
+        ActivityManager.RecentTaskInfo t6 = makeTaskInfo(6);
+        setRawList(t1, t2, t3, t4, t5, t6);
+
+        // Mark a couple pairs [t2, t4], [t3, t5]
+        SplitBounds pair1Bounds = new SplitBounds(new Rect(), new Rect(), 2, 4);
+        SplitBounds pair2Bounds = new SplitBounds(new Rect(), new Rect(), 3, 5);
+
+        mRecentTasksController.addSplitPair(t2.taskId, t4.taskId, pair1Bounds);
+        mRecentTasksController.addSplitPair(t3.taskId, t5.taskId, pair2Bounds);
+
+        mRecentTasksController.asRecentTasks()
+                .getRecentTasks(MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0, Runnable::run, consumer);
+        mMainExecutor.flushAll();
+
+        assertGroupedTasksListEquals(recentTasks[0],
+                t1.taskId, -1,
+                t2.taskId, t4.taskId,
+                t3.taskId, t5.taskId,
+                t6.taskId, -1);
+    }
+
+    @Test
     public void testGetRecentTasks_groupActiveFreeformTasks() {
         StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
-                DesktopMode.class).startMocking();
-        when(DesktopMode.isActive(any())).thenReturn(true);
+                DesktopModeStatus.class).startMocking();
+        when(DesktopModeStatus.isActive(any())).thenReturn(true);
 
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -296,7 +342,7 @@
         for (ActivityManager.RecentTaskInfo task : tasks) {
             rawList.add(task);
         }
-        doReturn(rawList).when(mRecentTasksController).getRawRecentTasks(anyInt(), anyInt(),
+        doReturn(rawList).when(mActivityTaskManager).getRecentTasks(anyInt(), anyInt(),
                 anyInt());
         return rawList;
     }
@@ -307,7 +353,7 @@
      * @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
      *                        the grouped task list
      */
-    private void assertGroupedTasksListEquals(ArrayList<GroupedRecentTaskInfo> recentTasks,
+    private void assertGroupedTasksListEquals(List<GroupedRecentTaskInfo> recentTasks,
             int... expectedTaskIds) {
         int[] flattenedTaskIds = new int[recentTasks.size() * 2];
         for (int i = 0; i < recentTasks.size(); i++) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 5a68361..55883ab 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -58,6 +58,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.sysui.ShellSharedConstants;
 import com.android.wm.shell.transition.Transitions;
 
 import org.junit.Before;
@@ -133,6 +134,15 @@
     }
 
     @Test
+    public void instantiateController_addExternalInterface() {
+        doReturn(mMainExecutor).when(mTaskOrganizer).getExecutor();
+        when(mDisplayController.getDisplayLayout(anyInt())).thenReturn(new DisplayLayout());
+        mSplitScreenController.onInit();
+        verify(mShellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_SPLIT_SCREEN), any(), any());
+    }
+
+    @Test
     public void testShouldAddMultipleTaskFlag_notInSplitScreen() {
         doReturn(false).when(mSplitScreenController).isSplitScreenVisible();
         doReturn(true).when(mSplitScreenController).isValidToEnterSplitScreen(any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
index 35515e3..90165d1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -36,7 +37,9 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.sysui.ShellSharedConstants;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -56,25 +59,34 @@
 
     private @Mock Context mContext;
     private @Mock DisplayManager mDisplayManager;
-    private @Mock ShellInit mShellInit;
+    private @Mock ShellController mShellController;
     private @Mock ShellTaskOrganizer mTaskOrganizer;
     private @Mock ShellExecutor mMainExecutor;
     private @Mock StartingWindowTypeAlgorithm mTypeAlgorithm;
     private @Mock IconProvider mIconProvider;
     private @Mock TransactionPool mTransactionPool;
     private StartingWindowController mController;
+    private ShellInit mShellInit;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         doReturn(mock(Display.class)).when(mDisplayManager).getDisplay(anyInt());
         doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
-        mController = new StartingWindowController(mContext, mShellInit, mTaskOrganizer,
-                mMainExecutor, mTypeAlgorithm, mIconProvider, mTransactionPool);
+        mShellInit = spy(new ShellInit(mMainExecutor));
+        mController = new StartingWindowController(mContext, mShellInit, mShellController,
+                mTaskOrganizer, mMainExecutor, mTypeAlgorithm, mIconProvider, mTransactionPool);
+        mShellInit.init();
     }
 
     @Test
-    public void instantiate_addInitCallback() {
+    public void instantiateController_addInitCallback() {
         verify(mShellInit, times(1)).addInitCallback(any(), any());
     }
+
+    @Test
+    public void instantiateController_addExternalInterface() {
+        verify(mShellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW), any(), any());
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
index d6ddba9..fbc50c6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
@@ -16,12 +16,16 @@
 
 package com.android.wm.shell.sysui;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
@@ -30,6 +34,7 @@
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.ExternalInterfaceBinder;
 import com.android.wm.shell.common.ShellExecutor;
 
 import org.junit.After;
@@ -49,6 +54,7 @@
 public class ShellControllerTest extends ShellTestCase {
 
     private static final int TEST_USER_ID = 100;
+    private static final String EXTRA_TEST_BINDER = "test_binder";
 
     @Mock
     private ShellInit mShellInit;
@@ -81,6 +87,47 @@
     }
 
     @Test
+    public void testAddExternalInterface_ensureCallback() {
+        Binder callback = new Binder();
+        ExternalInterfaceBinder wrapper = new ExternalInterfaceBinder() {
+            @Override
+            public void invalidate() {
+                // Do nothing
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return callback;
+            }
+        };
+        mController.addExternalInterface(EXTRA_TEST_BINDER, () -> wrapper, this);
+
+        Bundle b = new Bundle();
+        mController.asShell().createExternalInterfaces(b);
+        assertTrue(b.getIBinder(EXTRA_TEST_BINDER) == callback);
+    }
+
+    @Test
+    public void testAddExternalInterface_disallowDuplicateKeys() {
+        Binder callback = new Binder();
+        ExternalInterfaceBinder wrapper = new ExternalInterfaceBinder() {
+            @Override
+            public void invalidate() {
+                // Do nothing
+            }
+
+            @Override
+            public IBinder asBinder() {
+                return callback;
+            }
+        };
+        mController.addExternalInterface(EXTRA_TEST_BINDER, () -> wrapper, this);
+        assertThrows(IllegalArgumentException.class, () -> {
+            mController.addExternalInterface(EXTRA_TEST_BINDER, () -> wrapper, this);
+        });
+    }
+
+    @Test
     public void testAddUserChangeListener_ensureCallback() {
         mController.addUserChangeListener(mUserChangeListener);
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index c6492be..c764741 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -45,7 +45,6 @@
 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.eq;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.clearInvocations;
@@ -67,10 +66,12 @@
 import android.view.WindowManager;
 import android.window.IRemoteTransition;
 import android.window.IRemoteTransitionFinishedCallback;
+import android.window.IWindowContainerToken;
 import android.window.RemoteTransition;
 import android.window.TransitionFilter;
 import android.window.TransitionInfo;
 import android.window.TransitionRequestInfo;
+import android.window.WindowContainerToken;
 import android.window.WindowContainerTransaction;
 import android.window.WindowOrganizer;
 
@@ -86,7 +87,9 @@
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
+import com.android.wm.shell.sysui.ShellSharedConstants;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -117,18 +120,31 @@
     @Before
     public void setUp() {
         doAnswer(invocation -> invocation.getArguments()[1])
-                .when(mOrganizer).startTransition(anyInt(), any(), any());
+                .when(mOrganizer).startTransition(any(), any());
     }
 
     @Test
     public void instantiate_addInitCallback() {
         ShellInit shellInit = mock(ShellInit.class);
-        final Transitions t = new Transitions(mContext, shellInit, mOrganizer, mTransactionPool,
-                createTestDisplayController(), mMainExecutor, mMainHandler, mAnimExecutor);
+        final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
+                mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
+                mMainHandler, mAnimExecutor);
         verify(shellInit, times(1)).addInitCallback(any(), eq(t));
     }
 
     @Test
+    public void instantiateController_addExternalInterface() {
+        ShellInit shellInit = new ShellInit(mMainExecutor);
+        ShellController shellController = mock(ShellController.class);
+        final Transitions t = new Transitions(mContext, shellInit, shellController,
+                mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
+                mMainHandler, mAnimExecutor);
+        shellInit.init();
+        verify(shellController, times(1)).addExternalInterface(
+                eq(ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS), any(), any());
+    }
+
+    @Test
     public void testBasicTransitionFlow() {
         Transitions transitions = createTestTransitions();
         transitions.replaceDefaultHandlerForTest(mDefaultHandler);
@@ -136,7 +152,7 @@
         IBinder transitToken = new Binder();
         transitions.requestStartTransition(transitToken,
                 new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
-        verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
+        verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
         TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
                 .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
         transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
@@ -188,7 +204,7 @@
         // Make a request that will be rejected by the testhandler.
         transitions.requestStartTransition(transitToken,
                 new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
-        verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), isNull());
+        verify(mOrganizer, times(1)).startTransition(eq(transitToken), isNull());
         transitions.onTransitionReady(transitToken, open, mock(SurfaceControl.Transaction.class),
                 mock(SurfaceControl.Transaction.class));
         assertEquals(1, mDefaultHandler.activeCount());
@@ -199,10 +215,12 @@
         // Make a request that will be handled by testhandler but not animated by it.
         RunningTaskInfo mwTaskInfo =
                 createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
+        // Make the wct non-empty.
+        handlerWCT.setFocusable(new WindowContainerToken(mock(IWindowContainerToken.class)), true);
         transitions.requestStartTransition(transitToken,
                 new TransitionRequestInfo(TRANSIT_OPEN, mwTaskInfo, null /* remote */));
         verify(mOrganizer, times(1)).startTransition(
-                eq(TRANSIT_OPEN), eq(transitToken), eq(handlerWCT));
+                eq(transitToken), eq(handlerWCT));
         transitions.onTransitionReady(transitToken, open, mock(SurfaceControl.Transaction.class),
                 mock(SurfaceControl.Transaction.class));
         assertEquals(1, mDefaultHandler.activeCount());
@@ -217,8 +235,8 @@
         transitions.addHandler(topHandler);
         transitions.requestStartTransition(transitToken,
                 new TransitionRequestInfo(TRANSIT_CHANGE, mwTaskInfo, null /* remote */));
-        verify(mOrganizer, times(1)).startTransition(
-                eq(TRANSIT_CHANGE), eq(transitToken), eq(handlerWCT));
+        verify(mOrganizer, times(2)).startTransition(
+                eq(transitToken), eq(handlerWCT));
         TransitionInfo change = new TransitionInfoBuilder(TRANSIT_CHANGE)
                 .addChange(TRANSIT_CHANGE).build();
         transitions.onTransitionReady(transitToken, change, mock(SurfaceControl.Transaction.class),
@@ -256,7 +274,7 @@
         transitions.requestStartTransition(transitToken,
                 new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */,
                         new RemoteTransition(testRemote)));
-        verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
+        verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
         TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
                 .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
         transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
@@ -406,7 +424,7 @@
         IBinder transitToken = new Binder();
         transitions.requestStartTransition(transitToken,
                 new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
-        verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
+        verify(mOrganizer, times(1)).startTransition(eq(transitToken), any());
         TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
                 .addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
         transitions.onTransitionReady(transitToken, info, mock(SurfaceControl.Transaction.class),
@@ -1060,8 +1078,9 @@
 
     private Transitions createTestTransitions() {
         ShellInit shellInit = new ShellInit(mMainExecutor);
-        final Transitions t = new Transitions(mContext, shellInit, mOrganizer, mTransactionPool,
-                createTestDisplayController(), mMainExecutor, mMainHandler, mAnimExecutor);
+        final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class),
+                mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor,
+                mMainHandler, mAnimExecutor);
         shellInit.init();
         return t;
     }
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 ab6ac94..fa62b9c 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
@@ -77,6 +77,7 @@
 @RunWith(AndroidTestingRunner.class)
 public class WindowDecorationTests extends ShellTestCase {
     private static final int CAPTION_HEIGHT_DP = 32;
+    private static final int CAPTION_WIDTH_DP = 216;
     private static final int SHADOW_RADIUS_DP = 5;
     private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
     private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
@@ -220,7 +221,7 @@
 
         verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
         verify(captionContainerSurfaceBuilder).setContainerLayer();
-        verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
+        verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -46, 8);
         verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
         verify(mMockSurfaceControlStartT).show(captionContainerSurface);
 
@@ -410,7 +411,7 @@
         @Override
         void relayout(ActivityManager.RunningTaskInfo taskInfo) {
             relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP,
-                    mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT,
+                    CAPTION_WIDTH_DP, mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT,
                     mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult);
         }
     }
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 2aca41e..8e350d5 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 186998a..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 905d46e..cc2565d 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() {
@@ -130,7 +135,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 ada6af6..a6e685d 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -61,6 +61,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/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 1ebdc27..795af8a 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -300,7 +300,7 @@
         auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
 
         for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence,
-                          previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
+                  previousReleaseFence, transformHint, frameEvents, ignore] : surfaceControlStats) {
             ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
             aSurfaceControlStats[aSurfaceControl].acquireTimeOrFence = acquireTimeOrFence;
             aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
@@ -650,7 +650,7 @@
 
                 auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
                 for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence,
-                                  previousReleaseFence, transformHint, frameEvents] :
+                              previousReleaseFence, transformHint, frameEvents, ignore] :
                      surfaceControlStats) {
                     ASurfaceControl* aSurfaceControl =
                             reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_device.xml b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
index 0a5afe4..db54ae3 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_device.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_device.xml
@@ -29,7 +29,9 @@
         android:layout_width="24dp"
         android:layout_height="24dp"
         android:layout_marginStart="24dp"
-        android:tint="@android:color/system_accent1_600"/>
+        android:tint="@android:color/system_accent1_600"
+        android:importantForAccessibility="no"
+        android:contentDescription="@null"/>
 
     <TextView
         android:id="@android:id/text1"
diff --git a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
index 54916a2..a3d71b9 100644
--- a/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
+++ b/packages/CompanionDeviceManager/res/layout/list_item_permission.xml
@@ -30,7 +30,8 @@
         android:layout_height="24dp"
         android:layout_marginTop="8dp"
         android:layout_marginEnd="12dp"
-        android:contentDescription="Permission Icon"/>
+        android:importantForAccessibility="no"
+        android:contentDescription="@null"/>
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 7f33114..1c428aa 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -25,7 +25,7 @@
     <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="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="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>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index d62708e..2120515 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -25,7 +25,7 @@
     <string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
-    <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
+    <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 9a45788..d1d02b4 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -28,7 +28,7 @@
     <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>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
-    <string name="title_computer" msgid="4693714143506569253">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; مجاز می‌شود به این اطلاعات در دستگاهتان دسترسی پیدا کند"</string>
+    <string name="title_computer" msgid="4693714143506569253">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه دسترسی به این اطلاعات در دستگاهتان داده شود"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="permission_notification" msgid="693762568127741203">"اعلان‌ها"</string>
     <string name="permission_notification_summary" msgid="884075314530071011">"می‌تواند همه اعلان‌ها، ازجمله اطلاعاتی مثل مخاطبین، پیام‌ها، و عکس‌ها را بخواند"</string>
@@ -40,7 +40,7 @@
     <string name="summary_generic" msgid="2346762210105903720"></string>
     <string name="consent_yes" msgid="8344487259618762872">"اجازه دادن"</string>
     <string name="consent_no" msgid="2640796915611404382">"اجازه ندادن"</string>
-    <string name="consent_back" msgid="2560683030046918882">"برگشت"</string>
+    <string name="consent_back" msgid="2560683030046918882">"برگشتن"</string>
     <string name="permission_sync_confirmation_title" msgid="667074294393493186">"انتقال اجازه‌های برنامه به ساعت"</string>
     <string name="permission_sync_summary" msgid="8873391306499120778">"برای آسان‌تر کردن راه‌اندازی ساعت، برنامه‌های نصب‌شده در ساعت درحین راه‌اندازی از همان اجازه‌های تلفن استفاده خواهند کرد.\n\n ممکن است این اجازه‌ها شامل دسترسی به میکروفون و مکان ساعت باشد."</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"نماد برنامه"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index eaf0d54..aaaef4b 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -28,7 +28,7 @@
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para emitir contido de aplicacións entre os teus aparellos"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
-    <string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
+    <string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información do teu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string>
     <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index c5ef913..794aefe 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -31,7 +31,7 @@
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"इससे सभी सूचनाएं देखी जा सकती हैं. इसमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल होती है"</string>
+    <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 services"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index 525896b..b7f8b5e 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -28,7 +28,7 @@
     <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>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
-    <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용합니다."</string>
+    <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="permission_notification" msgid="693762568127741203">"알림"</string>
     <string name="permission_notification_summary" msgid="884075314530071011">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 6e59d5e..385474e 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -28,7 +28,7 @@
     <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>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
-    <string name="title_computer" msgid="4693714143506569253">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
+    <string name="title_computer" msgid="4693714143506569253">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="permission_notification" msgid="693762568127741203">"Известувања"</string>
     <string name="permission_notification_summary" msgid="884075314530071011">"може да ги чита сите известувања, вклучително и податоци како контакти, пораки и фотографии"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 1ed65bd..4eefbcd 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -28,10 +28,10 @@
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
-    <string name="title_computer" msgid="4693714143506569253">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
+    <string name="title_computer" msgid="4693714143506569253">"Permita que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
     <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contratos, mensagens e fotos"</string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contactos, mensagens e fotos"</string>
     <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string>
     <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index fa15045..d982d5f 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -17,15 +17,15 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4470785958457506021">"Manager de dispozitiv Companion"</string>
-    <string name="confirmation_title" msgid="3785000297483688997">"Permiteți ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să vă acceseze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
+    <string name="confirmation_title" msgid="3785000297483688997">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Alege un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările dvs. și să vă acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
+    <string name="summary_watch" msgid="3002344206574997652">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările și să acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
     <string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string>
     <string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
-    <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele dvs."</string>
+    <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele tale"</string>
     <string name="title_automotive_projection" msgid="3296005598978412847"></string>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
@@ -41,8 +41,8 @@
     <string name="consent_yes" msgid="8344487259618762872">"Permite"</string>
     <string name="consent_no" msgid="2640796915611404382">"Nu permite"</string>
     <string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
-    <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferați permisiunile pentru aplicații pe ceas"</string>
-    <string name="permission_sync_summary" msgid="8873391306499120778">"Ca să configurați mai ușor ceasul, aplicațiile instalate pe ceas în timpul procesului de configurare vor folosi aceleași permisiuni ca telefonul.\n\n Între acestea se poate număra accesul la microfonul și locația ceasului."</string>
+    <string name="permission_sync_confirmation_title" msgid="667074294393493186">"Transferă permisiunile pentru aplicații pe ceas"</string>
+    <string name="permission_sync_summary" msgid="8873391306499120778">"Ca să configurezi mai ușor ceasul, aplicațiile instalate pe ceas în timpul procesului de configurare vor folosi aceleași permisiuni ca telefonul.\n\n Între acestea se poate număra accesul la microfonul și locația ceasului."</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Pictograma aplicației"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Butonul Mai multe informații"</string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index d574cec..8f58d54 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -25,7 +25,7 @@
     <string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&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="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>
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
index fc5ff08..5c9ab7b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceDiscoveryService.java
@@ -103,7 +103,7 @@
 
     private final Runnable mTimeoutRunnable = this::timeout;
 
-    private boolean mStopAfterFirstMatch;;
+    private boolean mStopAfterFirstMatch;
 
     /**
      * A state enum for devices' discovery.
diff --git a/packages/DynamicSystemInstallationService/res/values-ro/strings.xml b/packages/DynamicSystemInstallationService/res/values-ro/strings.xml
index 22a46d5..a8a5125 100644
--- a/packages/DynamicSystemInstallationService/res/values-ro/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-ro/strings.xml
@@ -1,14 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="keyguard_description" msgid="8582605799129954556">"Introdu parola și accesați Actualizările de sistem dinamice"</string>
-    <string name="notification_install_completed" msgid="6252047868415172643">"Sistemul dinamic este pregătit. Ca să începeți să-l folosiți, reporniți dispozitivul."</string>
+    <string name="keyguard_description" msgid="8582605799129954556">"Introdu parola și accesează Actualizările de sistem dinamice"</string>
+    <string name="notification_install_completed" msgid="6252047868415172643">"Sistemul dinamic e pregătit. Ca să începi să-l folosești, repornește dispozitivul."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"Se instalează"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"Instalarea nu a reușit"</string>
-    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Nu s-a validat imaginea. Abandonați instalarea."</string>
+    <string name="notification_image_validation_failed" msgid="2720357826403917016">"Nu s-a validat imaginea. Abandonează instalarea."</string>
     <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"Rulăm un sistem dinamic. Repornește pentru a folosi versiunea Android inițială."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"Anulează"</string>
-    <string name="notification_action_discard" msgid="1817481003134947493">"Renunțați"</string>
+    <string name="notification_action_discard" msgid="1817481003134947493">"Renunță"</string>
     <string name="notification_action_reboot_to_dynsystem" msgid="4015817159115912479">"Repornește"</string>
     <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"Repornește"</string>
     <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"S-a renunțat la sistemul dinamic"</string>
diff --git a/packages/PackageInstaller/res/values-ro/strings.xml b/packages/PackageInstaller/res/values-ro/strings.xml
index 6b793fc..9ca4543 100644
--- a/packages/PackageInstaller/res/values-ro/strings.xml
+++ b/packages/PackageInstaller/res/values-ro/strings.xml
@@ -24,8 +24,8 @@
     <string name="installing" msgid="4921993079741206516">"Se instalează…"</string>
     <string name="installing_app" msgid="1165095864863849422">"Se instalează <xliff:g id="PACKAGE_LABEL">%1$s</xliff:g>…"</string>
     <string name="install_done" msgid="5987363587661783896">"Aplicație instalată."</string>
-    <string name="install_confirm_question" msgid="7663733664476363311">"Doriți să instalați această aplicație?"</string>
-    <string name="install_confirm_question_update" msgid="3348888852318388584">"Doriți să actualizați această aplicație?"</string>
+    <string name="install_confirm_question" msgid="7663733664476363311">"Vrei să instalezi această aplicație?"</string>
+    <string name="install_confirm_question_update" msgid="3348888852318388584">"Vrei să actualizezi această aplicație?"</string>
     <string name="install_failed" msgid="5777824004474125469">"Aplicația nu a fost instalată."</string>
     <string name="install_failed_blocked" msgid="8512284352994752094">"Instalarea pachetului a fost blocată."</string>
     <string name="install_failed_conflict" msgid="3493184212162521426">"Aplicația nu a fost instalată deoarece pachetul intră în conflict cu un pachet existent."</string>
@@ -56,7 +56,7 @@
     <string name="uninstall_application_text" msgid="3816830743706143980">"Dezinstalezi această aplicație?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"Dezinstalezi această aplicație pentru "<b>"toți"</b>" utilizatorii? Aplicația și datele acesteia vor fi eliminate de la "<b>"toți"</b>" utilizatorii de pe acest dispozitiv."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"Dezinstalezi această aplicație pentru utilizatorul <xliff:g id="USERNAME">%1$s</xliff:g>?"</string>
-    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Doriți să dezinstalați această aplicație din profilul de serviciu?"</string>
+    <string name="uninstall_application_text_current_user_work_profile" msgid="8788387739022366193">"Dezinstalezi această aplicație din profilul de serviciu?"</string>
     <string name="uninstall_update_text" msgid="863648314632448705">"Înlocuiești această aplicație cu versiunea din fabrică? Toate datele vor fi eliminate."</string>
     <string name="uninstall_update_text_multiuser" msgid="8992883151333057227">"Înlocuiești această aplicație cu versiunea din fabrică? Toate datele vor fi eliminate. Această acțiune va afecta toți utilizatorii dispozitivului, inclusiv pe cei cu profiluri de serviciu."</string>
     <string name="uninstall_keep_data" msgid="7002379587465487550">"Păstrează <xliff:g id="SIZE">%1$s</xliff:g> din datele aplicației."</string>
@@ -81,9 +81,9 @@
     <string name="wear_not_allowed_dlg_text" msgid="704615521550939237">"Acțiunile de instalare și dezinstalare nu sunt acceptate pe Wear."</string>
     <string name="message_staging" msgid="8032722385658438567">"Se pregătește aplicația…"</string>
     <string name="app_name_unknown" msgid="6881210203354323926">"Necunoscut"</string>
-    <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Din motive de securitate, tableta dvs. nu are permisiunea să instaleze aplicații necunoscute din această sursă. Puteți modifica această opțiune în Setări."</string>
-    <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Din motive de securitate, televizorul dvs. nu are permisiunea să instaleze aplicații necunoscute din această sursă. Puteți modifica această opțiune în Setări."</string>
-    <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Din motive de securitate, telefonul dvs. nu are permisiunea să instaleze aplicații necunoscute din această sursă. Puteți modifica această opțiune în Setări."</string>
+    <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Din motive de securitate, tableta nu are permisiunea să instaleze aplicații necunoscute din această sursă. Poți modifica această opțiune în setări."</string>
+    <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Din motive de securitate, televizorul nu are permisiunea să instaleze aplicații necunoscute din această sursă. Poți modifica această opțiune în setări."</string>
+    <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Din motive de securitate, telefonul nu are permisiunea să instaleze aplicații necunoscute din această sursă. Poți modifica această opțiune în setări."</string>
     <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Telefonul și datele tale personale sunt mai vulnerabile la un atac din partea aplicațiilor necunoscute. Dacă instalezi această aplicație, accepți că ești singura persoană responsabilă pentru deteriorarea telefonului sau pentru pierderea datelor, care pot avea loc în urma folosirii acesteia."</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Tableta și datele tale personale sunt mai vulnerabile la un atac din partea aplicațiilor necunoscute. Dacă instalezi aplicația, accepți că ești singura persoană responsabilă pentru deteriorarea tabletei sau pentru pierderea datelor, care pot avea loc în urma folosirii acesteia."</string>
     <string name="anonymous_source_warning" product="tv" msgid="5599483539528168566">"Televizorul și datele tale cu caracter personal sunt mai vulnerabile la un atac din partea aplicațiilor necunoscute. Dacă instalezi această aplicație, accepți că ești singura persoană responsabilă pentru deteriorarea televizorului sau pentru pierderea datelor, care pot avea loc în urma folosirii acesteia."</string>
diff --git a/packages/PrintSpooler/res/values-te/strings.xml b/packages/PrintSpooler/res/values-te/strings.xml
index e00e28c..3ab43f1 100644
--- a/packages/PrintSpooler/res/values-te/strings.xml
+++ b/packages/PrintSpooler/res/values-te/strings.xml
@@ -21,8 +21,8 @@
     <string name="label_destination" msgid="9132510997381599275">"గమ్యం"</string>
     <string name="label_copies" msgid="3634531042822968308">"కాపీలు"</string>
     <string name="label_copies_summary" msgid="3861966063536529540">"కాపీలు:"</string>
-    <string name="label_paper_size" msgid="908654383827777759">"కాగితపు పరిమాణం"</string>
-    <string name="label_paper_size_summary" msgid="5668204981332138168">"కాగితపు పరిమాణం:"</string>
+    <string name="label_paper_size" msgid="908654383827777759">"కాగితపు సైజ్‌"</string>
+    <string name="label_paper_size_summary" msgid="5668204981332138168">"కాగితపు సైజ్‌:"</string>
     <string name="label_color" msgid="1108690305218188969">"రంగు"</string>
     <string name="label_duplex" msgid="5370037254347072243">"రెండు వైపుల"</string>
     <string name="label_orientation" msgid="2853142581990496477">"ఓరియంటేషన్"</string>
@@ -40,7 +40,7 @@
     <string name="print_dialog" msgid="32628687461331979">"ముద్రణ డైలాగ్"</string>
     <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="PAGE_COUNT">%2$d</xliff:g>లో <xliff:g id="CURRENT_PAGE">%1$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="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="collapse_handle" msgid="6886637989442507451">"కుదింపు హ్యాండిల్"</string>
     <string name="print_button" msgid="645164566271246268">"ప్రింట్ చేయండి"</string>
diff --git a/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml b/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml
index 18b6a0e..ff260f5 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/values-ro/strings.xml
@@ -17,5 +17,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Respingeți"</string>
+    <string name="accessibility_banner_message_dismiss" msgid="5272928723898304168">"Închide"</string>
 </resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 0a64da3..b024a87 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -116,7 +116,7 @@
     <string name="bluetooth_profile_headset" msgid="5395952236133499331">"المكالمات الهاتفية"</string>
     <string name="bluetooth_profile_opp" msgid="6692618568149493430">"نقل الملف"</string>
     <string name="bluetooth_profile_hid" msgid="2969922922664315866">"جهاز الإرسال"</string>
-    <string name="bluetooth_profile_pan" msgid="1006235139308318188">"استخدام الإنترنت"</string>
+    <string name="bluetooth_profile_pan" msgid="1006235139308318188">"الوصول إلى الإنترنت"</string>
     <string name="bluetooth_profile_pbap" msgid="4262303387989406171">"مشاركة جهات الاتصال وسجل المكالمات"</string>
     <string name="bluetooth_profile_pbap_summary" msgid="6466456791354759132">"استخدام إعدادات بلوتوث لمشاركة جهات الاتصال وسجل المكالمات"</string>
     <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"مشاركة اتصال الإنترنت"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index d11ed3c..c4e9dd4 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -75,7 +75,7 @@
     <string name="wifi_limited_connection" msgid="1184778285475204682">"ইণ্টাৰনেট সংযোগ সীমিত"</string>
     <string name="wifi_status_no_internet" msgid="3799933875988829048">"ইণ্টাৰনেট সংযোগ নাই"</string>
     <string name="wifi_status_sign_in_required" msgid="2236267500459526855">"ছাইন ইন কৰা দৰকাৰী"</string>
-    <string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"একচেছ পইণ্ট কিছু সময়ৰ বাবে পূৰ্ণ হৈ আছে"</string>
+    <string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"এক্সেছ পইণ্ট সাময়িকভাৱে পূৰ্ণ হৈ আছে"</string>
     <string name="connected_via_carrier" msgid="1968057009076191514">"%1$sৰ যোগেৰে সংযোজিত"</string>
     <string name="available_via_carrier" msgid="465598683092718294">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
     <string name="osu_opening_provider" msgid="4318105381295178285">"<xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g> খুলি থকা হৈছে"</string>
@@ -98,7 +98,7 @@
     <string name="bluetooth_pairing" msgid="4269046942588193600">"যোৰা লগোৱা হৈছে…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"সংযোগ কৰা হ’ল (ফ\'ন নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"সংযোগ কৰা হ’ল (মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"সংযোগ কৰা হ’ল (বাৰ্তাত প্ৰৱেশাধিকাৰ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
+    <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"সংযোগ কৰা হ’ল (বাৰ্তাৰ এক্সেছ নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_headset_no_a2dp" msgid="2893204819854215433">"সংযোগ কৰা হ’ল (কোনো ফ\'ন বা মিডিয়া নাই)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_battery_level" msgid="5410325759372259950">"সংযোগ কৰা হ’ল, বেটাৰীৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"সংযোগ কৰা হ’ল (ফ\'ন নাই), বেটাৰীৰ স্তৰ <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string>
@@ -139,7 +139,7 @@
     <string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"ডিভাইচৰ সৈতে স্থানীয় ইণ্টাৰনেট সংযোগ শ্বেয়াৰ কৰা হৈছে"</string>
     <string name="bluetooth_pan_profile_summary_use_for" msgid="7422039765025340313">"ইণ্টাৰনেট চলাবলৈ ব্যৱহাৰ কৰক"</string>
     <string name="bluetooth_map_profile_summary_use_for" msgid="4453622103977592583">"মেপৰ বাবে ব্যৱহাৰ কৰক"</string>
-    <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"ছিমত প্ৰৱেশৰ বাবে ব্যৱহাৰ কৰক"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="6204902866176714046">"ছিমৰ এক্সেছৰ বাবে ব্যৱহাৰ কৰক"</string>
     <string name="bluetooth_a2dp_profile_summary_use_for" msgid="7324694226276491807">"মিডিয়া অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string>
     <string name="bluetooth_headset_profile_summary_use_for" msgid="808970643123744170">"ফ\'ন অডিঅ\'ৰ বাবে ব্যৱহাৰ কৰক"</string>
     <string name="bluetooth_opp_profile_summary_use_for" msgid="461981154387015457">"ফাইল স্থানান্তৰ কৰিবলৈ ব্যৱহাৰ কৰক"</string>
@@ -149,7 +149,7 @@
     <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"পেয়াৰ কৰক"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"পেয়াৰ কৰক"</string>
     <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"বাতিল কৰক"</string>
-    <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"যোৰা লগালে ইয়ে সংযোজিত কৰাৰ সময়ত আপোনাৰ সম্পৰ্কসমূহ আৰু কলৰ ইতিহাস চাবলৈ অনুমতি দিব।"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"পেয়াৰিঙে সংযোজিত হ\'লে আপোনাৰ সম্পৰ্ক আৰু কলৰ ইতিহাসৰ এক্সেছ প্ৰদান কৰে।"</string>
     <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ সৈতে পেয়াৰ কৰিব পৰা নগ’ল।"</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"এটা ভুল পিন বা পাছকীৰ কাৰণে <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ সৈতে পেয়াৰ কৰিব পৰা নাই।"</string>
     <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ সৈতে যোগাযোগ কৰিব পৰা নগ\'ল"</string>
@@ -342,7 +342,7 @@
     <string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"ব্লুটুথ Gabeldorche সুবিধাৰ সমষ্টিটো সক্ষম কৰে।"</string>
     <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"উন্নত সংযোগ সুবিধাটো সক্ষম কৰে।"</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"স্থানীয় টাৰ্মিনেল"</string>
-    <string name="enable_terminal_summary" msgid="2481074834856064500">"স্থানীয় শ্বেল প্ৰৱেশাধিকাৰ দিয়া টাৰ্মিনেল এপ্ সক্ষম কৰক"</string>
+    <string name="enable_terminal_summary" msgid="2481074834856064500">"স্থানীয় শ্বেলৰ এক্সেছ দিয়া টাৰ্মিনেল এপ্ সক্ষম কৰক"</string>
     <string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP পৰীক্ষণ"</string>
     <string name="hdcp_checking_dialog_title" msgid="7691060297616217781">"HDCP পৰীক্ষণ আচৰণ ছেট কৰক"</string>
     <string name="debug_debugging_category" msgid="535341063709248842">"ডিবাগিং"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 022fc05..3750254 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -268,7 +268,7 @@
     <string name="keep_screen_on" msgid="1187161672348797558">"Mantendu aktibo"</string>
     <string name="keep_screen_on_summary" msgid="1510731514101925829">"Pantaila ez da ezarriko inoiz inaktibo kargatu bitartean"</string>
     <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Gaitu Bluetooth HCI miatze-erregistroa"</string>
-    <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Hauteman Bluetooth paketeak (aktibatu edo desaktibatu Bluetooth-a ezarpena aldatu ostean)"</string>
+    <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Hauteman Bluetooth paketeak (aktibatu edo desaktibatu Bluetootha ezarpena aldatu ostean)"</string>
     <string name="oem_unlock_enable" msgid="5334869171871566731">"OEM desblokeoa"</string>
     <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Onartu abiarazlea desblokeatzea"</string>
     <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM desblokeoa onartu nahi duzu?"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b6eb82e..98cc18e 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -247,7 +247,7 @@
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"Appareils associés"</string>
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Actuellement connecté"</string>
     <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Infos sur l\'appareil"</string>
-    <string name="adb_device_forget" msgid="193072400783068417">"Retirer"</string>
+    <string name="adb_device_forget" msgid="193072400783068417">"Supprimer"</string>
     <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Empreinte de l\'appareil : <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
     <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Échec de la connexion"</string>
     <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Vérifiez que l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g> est connecté au bon réseau"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index a7618df..16ee8b8 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -54,7 +54,7 @@
     <string name="wifi_disabled_generic" msgid="2651916945380294607">"Slått av"</string>
     <string name="wifi_disabled_network_failure" msgid="2660396183242399585">"IP-konfigurasjonsfeil"</string>
     <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Ikke tilkoblet på grunn av nettverk av lav kvalitet"</string>
-    <string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"Wi-Fi-tilkoblingsfeil"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"Wifi-tilkoblingsfeil"</string>
     <string name="wifi_disabled_password_failure" msgid="6892387079613226738">"Autentiseringsproblem"</string>
     <string name="wifi_cant_connect" msgid="5718417542623056783">"Kan ikke koble til"</string>
     <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"Kan ikke koble til «<xliff:g id="AP_NAME">%1$s</xliff:g>»"</string>
@@ -161,12 +161,12 @@
     <string name="bluetooth_talkback_headphone" msgid="8613073829180337091">"Øretelefoner"</string>
     <string name="bluetooth_talkback_input_peripheral" msgid="5133944817800149942">"Inndata fra ytre utstyrsenheter"</string>
     <string name="bluetooth_talkback_bluetooth" msgid="1143241359781999989">"Bluetooth"</string>
-    <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi er av."</string>
-    <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi er frakoblet."</string>
-    <string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Wi-Fi-signal med én stolpe."</string>
-    <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi-signal med to stolper."</string>
-    <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi-signal med tre stolper."</string>
-    <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wi-Fi-signalet er ved full styrke."</string>
+    <string name="accessibility_wifi_off" msgid="1195445715254137155">"Wifi er av."</string>
+    <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wifi er frakoblet."</string>
+    <string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Wifi-signal med én stolpe."</string>
+    <string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wifi-signal med to stolper."</string>
+    <string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wifi-signal med tre stolper."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7165262794551355617">"Wifi-signalet er ved full styrke."</string>
     <string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Åpent nettverk"</string>
     <string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Sikkert nettverk"</string>
     <string name="process_kernel_label" msgid="950292573930336765">"Android-operativsystem"</string>
@@ -236,7 +236,7 @@
     <string name="enable_adb_summary" msgid="3711526030096574316">"Feilsøkingsmodus når USB kobles til"</string>
     <string name="clear_adb_keys" msgid="3010148733140369917">"USB-feilsøking – opphev autorisasjon"</string>
     <string name="enable_adb_wireless" msgid="6973226350963971018">"Trådløs feilsøking"</string>
-    <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Feilsøkingsmodus når Wi-Fi er tilkoblet"</string>
+    <string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Feilsøkingsmodus når Wifi er tilkoblet"</string>
     <string name="adb_wireless_error" msgid="721958772149779856">"Feil"</string>
     <string name="adb_wireless_settings" msgid="2295017847215680229">"Trådløs feilsøking"</string>
     <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"For å se og bruke tilgjengelige enheter, slå på trådløs feilsøking"</string>
@@ -255,13 +255,13 @@
     <string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Wi‑Fi-tilkoblingskode"</string>
     <string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Tilkoblingen mislyktes"</string>
     <string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Sørg for at enheten er koblet til samme nettverk."</string>
-    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via Wi-Fi ved å skanne en QR-kode"</string>
+    <string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Koble til enheten via Wifi ved å skanne en QR-kode"</string>
     <string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Kobler til enheten …"</string>
     <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Kunne ikke koble til enheten. Enten var QR-koden feil, eller enheten er ikke koblet til samme nettverk."</string>
     <string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"IP-adresse og port"</string>
     <string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Skann QR-koden"</string>
-    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via Wi-Fi ved å skanne en QR-kode"</string>
-    <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wi-Fi-nettverk"</string>
+    <string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Koble til enheten via Wifi ved å skanne en QR-kode"</string>
+    <string name="adb_wireless_no_network_msg" msgid="2365795244718494658">"Koble til et Wifi-nettverk"</string>
     <string name="keywords_adb_wireless" msgid="6507505581882171240">"adb, feilsøking, utvikler"</string>
     <string name="bugreport_in_power" msgid="8664089072534638709">"Snarvei til feilrapport"</string>
     <string name="bugreport_in_power_summary" msgid="1885529649381831775">"Vis en knapp for generering av feilrapport i batterimenyen"</string>
@@ -278,7 +278,7 @@
     <string name="mock_location_app_set" msgid="4706722469342913843">"App for fiktiv posisjon: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"Nettverk"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"Trådløs skjerm-sertifisering"</string>
-    <string name="wifi_verbose_logging" msgid="1785910450009679371">"Slå på detaljert Wi-Fi-loggføring"</string>
+    <string name="wifi_verbose_logging" msgid="1785910450009679371">"Slå på detaljert Wifi-loggføring"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Begrensning av Wi‑Fi-skanning"</string>
     <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Ikke-vedvarende tilfeldiggjøring av MAC-adresse for Wi‑Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Mobildata er alltid aktiv"</string>
@@ -310,7 +310,7 @@
     <string name="private_dns_mode_provider_hostname_hint" msgid="6564868953748514595">"Skriv inn DNS-leverandørens vertsnavn"</string>
     <string name="private_dns_mode_provider_failure" msgid="8356259467861515108">"Kunne ikke koble til"</string>
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Vis alternativer for sertifisering av trådløs skjerm"</string>
-    <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øk nivået av Wi-Fi-logging – vis per SSID RSSI i Wi-Fi-velgeren"</string>
+    <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Øk nivået av Wifi-logging – vis per SSID RSSI i Wifi-velgeren"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Reduserer batteriforbruket og forbedrer nettverksytelsen"</string>
     <string name="wifi_non_persistent_mac_randomization_summary" msgid="2159794543105053930">"Når denne modusen er slått på, kan MAC-adressen til denne enheten endres hver gang den kobler seg til et nettverk som har tilfeldiggjøring av MAC-adresse slått på."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Med datamåling"</string>
@@ -326,7 +326,7 @@
     <string name="allow_mock_location" msgid="2102650981552527884">"Tillat simulert posisjon"</string>
     <string name="allow_mock_location_summary" msgid="179780881081354579">"Tillat bruk av simulerte GPS-koordinater"</string>
     <string name="debug_view_attributes" msgid="3539609843984208216">"Slå på inspeksjon av visningsattributt"</string>
-    <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Ha alltid mobildata slått på, selv når Wi-Fi er aktiv (for hurtig nettverksbytting)."</string>
+    <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Ha alltid mobildata slått på, selv når Wifi er aktiv (for hurtig nettverksbytting)."</string>
     <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Bruk maskinvareakselerasjon for internettdeling hvis det er tilgjengelig"</string>
     <string name="adb_warning_title" msgid="7708653449506485728">"Tillate USB-feilsøking?"</string>
     <string name="adb_warning_message" msgid="8145270656419669221">"USB-feilsøking er bare ment for utviklingsformål. Bruk det til å kopiere data mellom datamaskinen og enheten, installere apper på enheten uten varsel og lese loggdata."</string>
@@ -571,7 +571,7 @@
     <string name="user_add_user_item_title" msgid="2394272381086965029">"Bruker"</string>
     <string name="user_add_profile_item_title" msgid="3111051717414643029">"Begrenset profil"</string>
     <string name="user_add_user_title" msgid="5457079143694924885">"Vil du legge til en ny bruker?"</string>
-    <string name="user_add_user_message_long" msgid="1527434966294733380">"Du kan dele denne enheten med andre folk ved å opprette flere brukere. Hver bruker har sin egen plass de kan tilpasse med apper, bakgrunner og annet. Brukere kan også justere enhetsinnstillinger, for eksempel Wi-Fi, som påvirker alle.\n\nNår du legger til en ny bruker, må vedkommende angi innstillinger for plassen sin.\n\nAlle brukere kan oppdatere apper for alle andre brukere. Innstillinger og tjenester for tilgjengelighet overføres kanskje ikke til den nye brukeren."</string>
+    <string name="user_add_user_message_long" msgid="1527434966294733380">"Du kan dele denne enheten med andre folk ved å opprette flere brukere. Hver bruker har sin egen plass de kan tilpasse med apper, bakgrunner og annet. Brukere kan også justere enhetsinnstillinger, for eksempel Wifi, som påvirker alle.\n\nNår du legger til en ny bruker, må vedkommende angi innstillinger for plassen sin.\n\nAlle brukere kan oppdatere apper for alle andre brukere. Innstillinger og tjenester for tilgjengelighet overføres kanskje ikke til den nye brukeren."</string>
     <string name="user_add_user_message_short" msgid="3295959985795716166">"Når du legger til en ny bruker, må hen konfigurere sitt eget område.\n\nAlle brukere kan oppdatere apper for alle andre brukere."</string>
     <string name="user_setup_dialog_title" msgid="8037342066381939995">"Konfigurere brukeren nå?"</string>
     <string name="user_setup_dialog_message" msgid="269931619868102841">"Sørg for at brukeren er tilgjengelig for å konfigurere området sitt på enheten"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index ca46d50d2..180b1fb 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -95,7 +95,7 @@
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Kopplar ifrån…"</string>
     <string name="bluetooth_connecting" msgid="5871702668260192755">"Ansluter…"</string>
     <string name="bluetooth_connected" msgid="8065345572198502293">"Ansluten<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
-    <string name="bluetooth_pairing" msgid="4269046942588193600">"Parkoppling…"</string>
+    <string name="bluetooth_pairing" msgid="4269046942588193600">"Parkopplar…"</string>
     <string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Ansluten (ingen mobil)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_a2dp" msgid="8566874395813947092">"Ansluten (inga medier)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
     <string name="bluetooth_connected_no_map" msgid="3381860077002724689">"Ansluten (ingen meddelandeåtkomst)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
index eff9e74..ee65ef4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
+++ b/packages/SettingsLib/src/com/android/settingslib/AccessibilityContentDescriptions.java
@@ -22,8 +22,11 @@
 public class AccessibilityContentDescriptions {
 
     private AccessibilityContentDescriptions() {}
+
+    public static final int PHONE_SIGNAL_STRENGTH_NONE = R.string.accessibility_no_phone;
+
     public static final int[] PHONE_SIGNAL_STRENGTH = {
-        R.string.accessibility_no_phone,
+        PHONE_SIGNAL_STRENGTH_NONE,
         R.string.accessibility_phone_one_bar,
         R.string.accessibility_phone_two_bars,
         R.string.accessibility_phone_three_bars,
diff --git a/packages/SettingsLib/src/com/android/settingslib/MobileNetworkTypeIcon.kt b/packages/SettingsLib/src/com/android/settingslib/MobileNetworkTypeIcon.kt
new file mode 100644
index 0000000..3daf8c2
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/MobileNetworkTypeIcon.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+
+/**
+ * A specification for the icon displaying the mobile network type -- 4G, 5G, LTE, etc. (aka "RAT
+ * icon" or "data type icon"). This is *not* the signal strength triangle.
+ *
+ * This is intended to eventually replace [SignalIcon.MobileIconGroup]. But for now,
+ * [MobileNetworkTypeIcons] just reads from the existing set of [SignalIcon.MobileIconGroup]
+ * instances to not duplicate data.
+ *
+ * TODO(b/238425913): Remove [SignalIcon.MobileIconGroup] and replace it with this class so that we
+ *   don't need to fill in the superfluous fields from its parent [SignalIcon.IconGroup] class. Then
+ *   this class can become either a sealed class or an enum with parameters.
+ */
+data class MobileNetworkTypeIcon(
+    /** A human-readable name for this network type, used for logging. */
+    val name: String,
+
+    /** The resource ID of the icon drawable to use. */
+    @DrawableRes val iconResId: Int,
+
+    /** The resource ID of the content description to use. */
+    @StringRes val contentDescriptionResId: Int,
+)
diff --git a/packages/SettingsLib/src/com/android/settingslib/MobileNetworkTypeIcons.kt b/packages/SettingsLib/src/com/android/settingslib/MobileNetworkTypeIcons.kt
new file mode 100644
index 0000000..2c5ee89
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/MobileNetworkTypeIcons.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
+
+import com.android.settingslib.mobile.TelephonyIcons.ICON_NAME_TO_ICON
+
+/**
+ * A utility class to fetch instances of [MobileNetworkTypeIcon] given a
+ * [SignalIcon.MobileIconGroup].
+ *
+ * Use [getNetworkTypeIcon] to fetch the instances.
+ */
+class MobileNetworkTypeIcons {
+    companion object {
+        /**
+         * A map from a [SignalIcon.MobileIconGroup.name] to an instance of [MobileNetworkTypeIcon],
+         * which is the preferred class going forward.
+         */
+        private val MOBILE_NETWORK_TYPE_ICONS: Map<String, MobileNetworkTypeIcon>
+
+        init {
+            // Build up the mapping from the old implementation to the new one.
+            val tempMap: MutableMap<String, MobileNetworkTypeIcon> = mutableMapOf()
+
+            ICON_NAME_TO_ICON.forEach { (_, mobileIconGroup) ->
+                tempMap[mobileIconGroup.name] = mobileIconGroup.toNetworkTypeIcon()
+            }
+
+            MOBILE_NETWORK_TYPE_ICONS = tempMap
+        }
+
+        /**
+         * A converter function between the old mobile network type icon implementation and the new
+         * one. Given an instance of the old class [mobileIconGroup], outputs an instance of the
+         * new class [MobileNetworkTypeIcon].
+         */
+        @JvmStatic
+        fun getNetworkTypeIcon(
+            mobileIconGroup: SignalIcon.MobileIconGroup
+        ): MobileNetworkTypeIcon {
+            return MOBILE_NETWORK_TYPE_ICONS[mobileIconGroup.name]
+                ?: mobileIconGroup.toNetworkTypeIcon()
+        }
+
+        private fun SignalIcon.MobileIconGroup.toNetworkTypeIcon(): MobileNetworkTypeIcon {
+            return MobileNetworkTypeIcon(
+                name = this.name,
+                iconResId = this.dataType,
+                contentDescriptionResId = this.dataContentDescription
+            )
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java b/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java
index 280e407..6aaab3c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SignalIcon.java
@@ -15,6 +15,9 @@
  */
 package com.android.settingslib;
 
+import androidx.annotation.DrawableRes;
+import androidx.annotation.StringRes;
+
 /**
  * Icons for SysUI and Settings.
  */
@@ -66,34 +69,31 @@
     }
 
     /**
-     * Holds icons for a given MobileState.
+     * Holds RAT icons for a given MobileState.
      */
     public static class MobileIconGroup extends IconGroup {
-        public final int dataContentDescription; // mContentDescriptionDataType
-        public final int dataType;
+        @StringRes public final int dataContentDescription;
+        @DrawableRes public final int dataType;
 
         public MobileIconGroup(
                 String name,
-                int[][] sbIcons,
-                int[][] qsIcons,
-                int[] contentDesc,
-                int sbNullState,
-                int qsNullState,
-                int sbDiscState,
-                int qsDiscState,
-                int discContentDesc,
                 int dataContentDesc,
                 int dataType
         ) {
             super(name,
-                    sbIcons,
-                    qsIcons,
-                    contentDesc,
-                    sbNullState,
-                    qsNullState,
-                    sbDiscState,
-                    qsDiscState,
-                    discContentDesc);
+                    // The rest of the values are the same for every type of MobileIconGroup, so
+                    // just provide them here.
+                    // TODO(b/238425913): Eventually replace with {@link MobileNetworkTypeIcon} so
+                    //  that we don't have to fill in these superfluous fields.
+                    /* sbIcons= */ null,
+                    /* qsIcons= */ null,
+                    /* contentDesc= */ AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+                    /* sbNullState= */ 0,
+                    /* qsNullState= */ 0,
+                    /* sbDiscState= */ 0,
+                    /* qsDiscState= */ 0,
+                    /* discContentDesc= */
+                        AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH_NONE);
             this.dataContentDescription = dataContentDesc;
             this.dataType = dataType;
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7927c5d..eb53ea1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -758,16 +758,23 @@
     }
 
     public boolean isBusy() {
-        synchronized (mProfileLock) {
-            for (LocalBluetoothProfile profile : mProfiles) {
-                int status = getProfileConnectionState(profile);
-                if (status == BluetoothProfile.STATE_CONNECTING
-                        || status == BluetoothProfile.STATE_DISCONNECTING) {
-                    return true;
-                }
+        for (CachedBluetoothDevice memberDevice : getMemberDevice()) {
+            if (isBusyState(memberDevice)) {
+                return true;
             }
-            return getBondState() == BluetoothDevice.BOND_BONDING;
         }
+        return isBusyState(this);
+    }
+
+    private boolean isBusyState(CachedBluetoothDevice device){
+        for (LocalBluetoothProfile profile : device.getProfiles()) {
+            int status = device.getProfileConnectionState(profile);
+            if (status == BluetoothProfile.STATE_CONNECTING
+                    || status == BluetoothProfile.STATE_DISCONNECTING) {
+                return true;
+            }
+        }
+        return device.getBondState() == BluetoothDevice.BOND_BONDING;
     }
 
     private boolean updateProfiles() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
index 23e0923..094567c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
+++ b/packages/SettingsLib/src/com/android/settingslib/mobile/TelephonyIcons.java
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.mobile;
 
-import com.android.settingslib.AccessibilityContentDescriptions;
 import com.android.settingslib.R;
 import com.android.settingslib.SignalIcon.MobileIconGroup;
 
@@ -49,297 +48,129 @@
 
     public static final MobileIconGroup CARRIER_NETWORK_CHANGE = new MobileIconGroup(
             "CARRIER_NETWORK_CHANGE",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.carrier_network_change_mode,
-            0
+            /* dataType= */ 0
     );
 
     public static final MobileIconGroup THREE_G = new MobileIconGroup(
             "3G",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_3g,
             TelephonyIcons.ICON_3G
     );
 
     public static final MobileIconGroup WFC = new MobileIconGroup(
             "WFC",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
-            0,
-            0);
+            /* dataContentDescription= */ 0,
+            /* dataType= */ 0);
 
     public static final MobileIconGroup UNKNOWN = new MobileIconGroup(
             "Unknown",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
-            0,
-            0);
+            /* dataContentDescription= */ 0,
+            /* dataType= */ 0);
 
     public static final MobileIconGroup E = new MobileIconGroup(
             "E",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_edge,
             TelephonyIcons.ICON_E
     );
 
     public static final MobileIconGroup ONE_X = new MobileIconGroup(
             "1X",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_cdma,
             TelephonyIcons.ICON_1X
     );
 
     public static final MobileIconGroup G = new MobileIconGroup(
             "G",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_gprs,
             TelephonyIcons.ICON_G
     );
 
     public static final MobileIconGroup H = new MobileIconGroup(
             "H",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_3_5g,
             TelephonyIcons.ICON_H
     );
 
     public static final MobileIconGroup H_PLUS = new MobileIconGroup(
             "H+",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_3_5g_plus,
             TelephonyIcons.ICON_H_PLUS
     );
 
     public static final MobileIconGroup FOUR_G = new MobileIconGroup(
             "4G",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_4g,
             TelephonyIcons.ICON_4G
     );
 
     public static final MobileIconGroup FOUR_G_PLUS = new MobileIconGroup(
             "4G+",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_4g_plus,
             TelephonyIcons.ICON_4G_PLUS
     );
 
     public static final MobileIconGroup LTE = new MobileIconGroup(
             "LTE",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_lte,
             TelephonyIcons.ICON_LTE
     );
 
     public static final MobileIconGroup LTE_PLUS = new MobileIconGroup(
             "LTE+",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_lte_plus,
             TelephonyIcons.ICON_LTE_PLUS
     );
 
     public static final MobileIconGroup FOUR_G_LTE = new MobileIconGroup(
             "4G LTE",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_4g_lte,
             TelephonyIcons.ICON_4G_LTE
     );
 
     public static final MobileIconGroup FOUR_G_LTE_PLUS = new MobileIconGroup(
             "4G LTE+",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_4g_lte_plus,
             TelephonyIcons.ICON_4G_LTE_PLUS
     );
 
     public static final MobileIconGroup LTE_CA_5G_E = new MobileIconGroup(
             "5Ge",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_5ge_html,
             TelephonyIcons.ICON_5G_E
     );
 
     public static final MobileIconGroup NR_5G = new MobileIconGroup(
             "5G",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_5g,
             TelephonyIcons.ICON_5G
     );
 
     public static final MobileIconGroup NR_5G_PLUS = new MobileIconGroup(
             "5G_PLUS",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_5g_plus,
             TelephonyIcons.ICON_5G_PLUS
     );
 
     public static final MobileIconGroup DATA_DISABLED = new MobileIconGroup(
             "DataDisabled",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.cell_data_off_content_description,
             0
     );
 
     public static final MobileIconGroup NOT_DEFAULT_DATA = new MobileIconGroup(
             "NotDefaultData",
-            null,
-            null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            0,
-            0,
-            0,
-            0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.not_default_data_content_description,
-            0
+            /* dataType= */ 0
     );
 
     public static final MobileIconGroup CARRIER_MERGED_WIFI = new MobileIconGroup(
             "CWF",
-            /* sbIcons= */ null,
-            /* qsIcons= */ null,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
-            /* sbNullState= */ 0,
-            /* qsNullState= */ 0,
-            /* sbDiscState= */ 0,
-            /* qsDiscState= */ 0,
-            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
             R.string.data_connection_carrier_wifi,
             TelephonyIcons.ICON_CWF
     );
 
-    // When adding a new MobileIconGround, check if the dataContentDescription has to be filtered
+    // When adding a new MobileIconGroup, check if the dataContentDescription has to be filtered
     // in QSCarrier#hasValidTypeContentDescription
 
     /** Mapping icon name(lower case) to the icon object. */
@@ -368,14 +199,6 @@
         ICON_NAME_TO_ICON.put("notdefaultdata", NOT_DEFAULT_DATA);
     }
 
-    public static final int[] WIFI_CALL_STRENGTH_ICONS = {
-        R.drawable.ic_wifi_call_strength_0,
-        R.drawable.ic_wifi_call_strength_1,
-        R.drawable.ic_wifi_call_strength_2,
-        R.drawable.ic_wifi_call_strength_3,
-        R.drawable.ic_wifi_call_strength_4
-    };
-
     public static final int[] MOBILE_CALL_STRENGTH_ICONS = {
         R.drawable.ic_mobile_call_strength_0,
         R.drawable.ic_mobile_call_strength_1,
@@ -384,4 +207,3 @@
         R.drawable.ic_mobile_call_strength_4
     };
 }
-
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/MobileNetworkTypeIconsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/MobileNetworkTypeIconsTest.java
new file mode 100644
index 0000000..39977df
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/MobileNetworkTypeIconsTest.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.settingslib;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.settingslib.mobile.TelephonyIcons;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class MobileNetworkTypeIconsTest {
+
+    @Test
+    public void getNetworkTypeIcon_hPlus_returnsHPlus() {
+        MobileNetworkTypeIcon icon =
+                MobileNetworkTypeIcons.getNetworkTypeIcon(TelephonyIcons.H_PLUS);
+
+        assertThat(icon.getName()).isEqualTo(TelephonyIcons.H_PLUS.name);
+        assertThat(icon.getIconResId()).isEqualTo(TelephonyIcons.ICON_H_PLUS);
+    }
+
+    @Test
+    public void getNetworkTypeIcon_fourG_returnsFourG() {
+        MobileNetworkTypeIcon icon =
+                MobileNetworkTypeIcons.getNetworkTypeIcon(TelephonyIcons.FOUR_G);
+
+        assertThat(icon.getName()).isEqualTo(TelephonyIcons.H_PLUS.name);
+        assertThat(icon.getIconResId()).isEqualTo(TelephonyIcons.ICON_4G);
+    }
+
+    @Test
+    public void getNetworkTypeIcon_unknown_returnsUnknown() {
+        SignalIcon.MobileIconGroup unknownGroup =
+                new SignalIcon.MobileIconGroup("testUnknownNameHere", 45, 6);
+
+        MobileNetworkTypeIcon icon = MobileNetworkTypeIcons.getNetworkTypeIcon(unknownGroup);
+
+        assertThat(icon.getName()).isEqualTo("testUnknownNameHere");
+        assertThat(icon.getIconResId()).isEqualTo(45);
+        assertThat(icon.getContentDescriptionResId()).isEqualTo(6);
+    }
+}
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 79e9938..315ab0a 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
@@ -1069,4 +1069,80 @@
         assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
         assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
     }
+
+    @Test
+    public void isBusy_mainDeviceIsConnecting_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_mainDeviceIsBonding_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_memberDeviceIsConnecting_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_memberDeviceIsBonding_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_allDevicesAreNotBusy_returnsNotBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isFalse();
+    }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index a6bfc408b..76cee7b 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -44,8 +44,6 @@
         Settings.System.DIM_SCREEN,
         Settings.System.SCREEN_OFF_TIMEOUT,
         Settings.System.SCREEN_BRIGHTNESS_MODE,
-        Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
-        Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
         Settings.System.ADAPTIVE_SLEEP,             // moved to secure
         Settings.System.APPLY_RAMPING_RINGER,
         Settings.System.VIBRATE_INPUT_DEVICES,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 8e82b8b..8b9d118 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -102,7 +102,9 @@
                     Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.SCREEN_BRIGHTNESS_FLOAT,
+                    Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
                     Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT,
+                    Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ,
                     Settings.System.MULTI_AUDIO_FOCUS_ENABLED, // form-factor/OEM specific
                     Settings.System.WEAR_ACCESSIBILITY_GESTURE_ENABLED
                     );
diff --git a/packages/SimAppDialog/res/values-ro/strings.xml b/packages/SimAppDialog/res/values-ro/strings.xml
index 5d876ea..2117191 100644
--- a/packages/SimAppDialog/res/values-ro/strings.xml
+++ b/packages/SimAppDialog/res/values-ro/strings.xml
@@ -19,8 +19,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="8898068901680117589">"Sim App Dialog"</string>
     <string name="install_carrier_app_title" msgid="334729104862562585">"Activează serviciul mobil"</string>
-    <string name="install_carrier_app_description" msgid="4014303558674923797">"Pentru ca noul card SIM să funcționeze corect, va trebui să instalați aplicația <xliff:g id="ID_1">%1$s</xliff:g>"</string>
-    <string name="install_carrier_app_description_default" msgid="7356830245205847840">"Pentru ca noul card SIM să funcționeze corect, va trebui să instalați aplicația operatorului"</string>
+    <string name="install_carrier_app_description" msgid="4014303558674923797">"Pentru ca noul card SIM să funcționeze corect, va trebui să instalezi aplicația <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="install_carrier_app_description_default" msgid="7356830245205847840">"Pentru ca noul card SIM să funcționeze corect, va trebui să instalezi aplicația operatorului"</string>
     <string name="install_carrier_app_defer_action" msgid="2558576736886876209">"Nu acum"</string>
     <string name="install_carrier_app_download_action" msgid="7859229305958538064">"Descarcă aplicația"</string>
 </resources>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index df6f08d..2f5b5f4 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -294,5 +294,6 @@
     dxflags: ["--multi-dex"],
     required: [
         "privapp_whitelist_com.android.systemui",
+        "wmshell.protolog.json.gz",
     ],
 }
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 26feaf9..cd45b8ea 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -1,25 +1,6 @@
 {
   // Looking for unit test presubmit configuration?
   // This currently lives in ATP config apct/system_ui/unit_test
-  "presubmit-large": [
-    {
-      "name": "PlatformScenarioTests",
-      "options": [
-        {
-            "include-filter": "android.platform.test.scenario.sysui"
-        },
-        {
-            "include-annotation": "android.platform.test.scenario.annotation.Scenario"
-        },
-        {
-            "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-            "exclude-annotation": "android.platform.test.annotations.Postsubmit"
-        }
-      ]
-    }
-  ],
   "presubmit-sysui": [
     {
       "name": "PlatformScenarioTests",
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
index eb000ad..0028d13 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewLaunchAnimatorController.kt
@@ -199,6 +199,10 @@
         // the content before fading out the background.
         ghostView = GhostView.addGhost(ghostedView, launchContainer)
 
+        // The ghost was just created, so ghostedView is currently invisible. We need to make sure
+        // that it stays invisible as long as we are animating.
+        (ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(true)
+
         val matrix = ghostView?.animationMatrix ?: Matrix.IDENTITY_MATRIX
         matrix.getValues(initialGhostViewMatrixValues)
 
@@ -293,6 +297,7 @@
         backgroundDrawable?.wrapped?.alpha = startBackgroundAlpha
 
         GhostView.removeGhost(ghostedView)
+        (ghostedView as? LaunchableView)?.setShouldBlockVisibilityChanges(false)
         launchContainerOverlay.remove(backgroundView)
 
         // Make sure that the view is considered VISIBLE by accessibility by first making it
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
index dc2c6356..1b7e26b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewHierarchyAnimator.kt
@@ -361,13 +361,17 @@
          *
          * The end state of the animation is controlled by [destination]. This value can be any of
          * the four corners, any of the four edges, or the center of the view.
+         *
+         * @param onAnimationEnd an optional runnable that will be run once the animation finishes
+         *    successfully. Will not be run if the animation is cancelled.
          */
         @JvmOverloads
         fun animateRemoval(
             rootView: View,
             destination: Hotspot = Hotspot.CENTER,
             interpolator: Interpolator = DEFAULT_REMOVAL_INTERPOLATOR,
-            duration: Long = DEFAULT_DURATION
+            duration: Long = DEFAULT_DURATION,
+            onAnimationEnd: Runnable? = null,
         ): Boolean {
             if (
                 !occupiesSpace(
@@ -391,13 +395,28 @@
                 addListener(child, listener, recursive = false)
             }
 
-            // Remove the view so that a layout update is triggered for the siblings and they
-            // animate to their next position while the view's removal is also animating.
-            parent.removeView(rootView)
-            // By adding the view to the overlay, we can animate it while it isn't part of the view
-            // hierarchy. It is correctly positioned because we have its previous bounds, and we set
-            // them manually during the animation.
-            parent.overlay.add(rootView)
+            val viewHasSiblings = parent.childCount > 1
+            if (viewHasSiblings) {
+                // Remove the view so that a layout update is triggered for the siblings and they
+                // animate to their next position while the view's removal is also animating.
+                parent.removeView(rootView)
+                // By adding the view to the overlay, we can animate it while it isn't part of the
+                // view hierarchy. It is correctly positioned because we have its previous bounds,
+                // and we set them manually during the animation.
+                parent.overlay.add(rootView)
+            }
+            // If this view has no siblings, the parent view may shrink to (0,0) size and mess
+            // up the animation if we immediately remove the view. So instead, we just leave the
+            // view in the real hierarchy until the animation finishes.
+
+            val endRunnable = Runnable {
+                if (viewHasSiblings) {
+                    parent.overlay.remove(rootView)
+                } else {
+                    parent.removeView(rootView)
+                }
+                onAnimationEnd?.run()
+            }
 
             val startValues =
                 mapOf(
@@ -430,7 +449,8 @@
                 endValues,
                 interpolator,
                 duration,
-                ephemeral = true
+                ephemeral = true,
+                endRunnable,
             )
 
             if (rootView is ViewGroup) {
@@ -463,7 +483,6 @@
                                 .alpha(0f)
                                 .setInterpolator(Interpolators.ALPHA_OUT)
                                 .setDuration(duration / 2)
-                                .withEndAction { parent.overlay.remove(rootView) }
                                 .start()
                         }
                     }
@@ -477,7 +496,6 @@
                     .setInterpolator(Interpolators.ALPHA_OUT)
                     .setDuration(duration / 2)
                     .setStartDelay(duration / 2)
-                    .withEndAction { parent.overlay.remove(rootView) }
                     .start()
             }
 
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/NonInjectedServiceDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/NonInjectedServiceDetector.kt
new file mode 100644
index 0000000..4eb7c7d
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/NonInjectedServiceDetector.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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
+
+/** Detects usage of Context.getSystemService() and suggests to use an injected instance instead. */
+@Suppress("UnstableApiUsage")
+class NonInjectedServiceDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> {
+        return listOf("getSystemService")
+    }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        val evaluator = context.evaluator
+        if (
+            !evaluator.isStatic(method) &&
+                method.name == "getSystemService" &&
+                method.containingClass?.qualifiedName == "android.content.Context"
+        ) {
+            context.report(
+                ISSUE,
+                method,
+                context.getNameLocation(node),
+                "Use @Inject to get the handle to a system-level services instead of using " +
+                    "Context.getSystemService()"
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE: Issue =
+            Issue.create(
+                id = "NonInjectedService",
+                briefDescription =
+                    "System-level services should be retrieved using " +
+                        "@Inject instead of Context.getSystemService().",
+                explanation =
+                    "Context.getSystemService() should be avoided because it makes testing " +
+                        "difficult. Instead, use an injected service. For example, " +
+                        "instead of calling Context.getSystemService(UserManager.class), " +
+                        "use @Inject and add UserManager to the constructor",
+                category = Category.CORRECTNESS,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                    Implementation(NonInjectedServiceDetector::class.java, Scope.JAVA_FILE_SCOPE)
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
index b72d03d..eb71d32 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RegisterReceiverViaContextDetector.kt
@@ -27,6 +27,7 @@
 import com.intellij.psi.PsiMethod
 import org.jetbrains.uast.UCallExpression
 
+@Suppress("UnstableApiUsage")
 class RegisterReceiverViaContextDetector : Detector(), SourceCodeScanner {
 
     override fun getApplicableMethodNames(): List<String> {
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 4879883..312810b 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
@@ -35,6 +35,7 @@
                 GetMainLooperViaContextDetector.ISSUE,
                 RegisterReceiverViaContextDetector.ISSUE,
                 SoftwareBitmapDetector.ISSUE,
+                NonInjectedServiceDetector.ISSUE,
         )
 
     override val api: Int
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt
new file mode 100644
index 0000000..26bd8d0
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest.java
+
+/*
+ * This file contains stubs of framework APIs and System UI classes for testing purposes only. The
+ * stubs are not used in the lint detectors themselves.
+ */
+@Suppress("UnstableApiUsage")
+internal val androidStubs =
+    arrayOf(
+        java(
+            """
+package android.app;
+
+public class ActivityManager {
+    public static int getCurrentUser() {}
+}
+"""
+        ),
+        java(
+            """
+package android.os;
+import android.content.pm.UserInfo;
+import android.annotation.UserIdInt;
+
+public class UserManager {
+    public UserInfo getUserInfo(@UserIdInt int userId) {}
+}
+"""
+        ),
+        java("""
+package android.annotation;
+
+public @interface UserIdInt {}
+"""),
+        java("""
+package android.content.pm;
+
+public class UserInfo {}
+"""),
+        java("""
+package android.os;
+
+public class Looper {}
+"""),
+        java("""
+package android.os;
+
+public class Handler {}
+"""),
+        java("""
+package android.content;
+
+public class ServiceConnection {}
+"""),
+        java("""
+package android.os;
+
+public enum UserHandle {
+    ALL
+}
+"""),
+        java(
+            """
+package android.content;
+import android.os.UserHandle;
+import android.os.Handler;
+import android.os.Looper;
+import java.util.concurrent.Executor;
+
+public class Context {
+    public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {}
+    public void registerReceiverAsUser(
+            BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
+            String broadcastPermission, Handler scheduler) {}
+    public void registerReceiverForAllUsers(
+            BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission,
+            Handler scheduler) {}
+    public void sendBroadcast(Intent intent) {}
+    public void sendBroadcast(Intent intent, String receiverPermission) {}
+    public void sendBroadcastAsUser(Intent intent, UserHandle userHandle, String permission) {}
+    public void bindService(Intent intent) {}
+    public void bindServiceAsUser(
+            Intent intent, ServiceConnection connection, int flags, UserHandle userHandle) {}
+    public void unbindService(ServiceConnection connection) {}
+    public Looper getMainLooper() { return null; }
+    public Executor getMainExecutor() { return null; }
+    public Handler getMainThreadHandler() { return null; }
+    public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) { return null; }
+    public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
+}
+"""
+        ),
+        java(
+            """
+package android.app;
+import android.content.Context;
+
+public class Activity extends Context {}
+"""
+        ),
+        java(
+            """
+package android.graphics;
+
+public class Bitmap {
+    public enum Config {
+        ARGB_8888,
+        RGB_565,
+        HARDWARE
+    }
+    public static Bitmap createBitmap(int width, int height, Config config) {
+        return null;
+    }
+}
+"""
+        ),
+        java("""
+package android.content;
+
+public class BroadcastReceiver {}
+"""),
+        java("""
+package android.content;
+
+public class IntentFilter {}
+"""),
+        java(
+            """
+package com.android.systemui.settings;
+import android.content.pm.UserInfo;
+
+public interface UserTracker {
+    int getUserId();
+    UserInfo getUserInfo();
+}
+"""
+        ),
+    )
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/BindServiceViaContextDetectorTest.kt
similarity index 61%
rename from packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt
rename to packages/SystemUI/checks/tests/com/android/internal/systemui/lint/BindServiceViaContextDetectorTest.kt
index bf685f7..564afcb 100644
--- a/packages/SystemUI/checks/tests/com/android/systemui/lint/BindServiceViaContextDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/BindServiceViaContextDetectorTest.kt
@@ -17,26 +17,26 @@
 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
 
+@Suppress("UnstableApiUsage")
 class BindServiceViaContextDetectorTest : LintDetectorTest() {
 
     override fun getDetector(): Detector = BindServiceViaContextDetector()
     override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
 
-    override fun getIssues(): List<Issue> = listOf(
-            BindServiceViaContextDetector.ISSUE)
+    override fun getIssues(): List<Issue> = listOf(BindServiceViaContextDetector.ISSUE)
 
     private val explanation = "Binding or unbinding services are synchronous calls"
 
     @Test
     fun testBindService() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -49,17 +49,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(BindServiceViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(BindServiceViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
     @Test
     fun testBindServiceAsUser() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -73,17 +76,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(BindServiceViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(BindServiceViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
     @Test
     fun testUnbindService() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -96,45 +102,15 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(BindServiceViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(BindServiceViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
-    private val contextStub: TestFile = java(
-            """
-        package android.content;
-        import android.os.UserHandle;
-
-        public class Context {
-            public void bindService(Intent intent) {};
-            public void bindServiceAsUser(Intent intent, ServiceConnection connection, int flags,
-                                          UserHandle userHandle) {};
-            public void unbindService(ServiceConnection connection) {};
-        }
-        """
-    )
-
-    private val serviceConnectionStub: TestFile = java(
-            """
-        package android.content;
-
-        public class ServiceConnection {}
-        """
-    )
-
-    private val userHandleStub: TestFile = java(
-            """
-        package android.os;
-
-        public enum UserHandle {
-            ALL
-        }
-        """
-    )
-
-    private val stubs = arrayOf(contextStub, serviceConnectionStub, userHandleStub)
+    private val stubs = androidStubs
 }
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/BroadcastSentViaContextDetectorTest.kt
similarity index 62%
rename from packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt
rename to packages/SystemUI/checks/tests/com/android/internal/systemui/lint/BroadcastSentViaContextDetectorTest.kt
index da010212f2..06aee8e 100644
--- a/packages/SystemUI/checks/tests/com/android/systemui/lint/BroadcastSentViaContextDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/BroadcastSentViaContextDetectorTest.kt
@@ -1,26 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.checks.infrastructure.LintDetectorTest
 import com.android.tools.lint.checks.infrastructure.TestFiles
-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
 import org.junit.Test
 
+@Suppress("UnstableApiUsage")
 class BroadcastSentViaContextDetectorTest : LintDetectorTest() {
 
     override fun getDetector(): Detector = BroadcastSentViaContextDetector()
     override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
 
-    override fun getIssues(): List<Issue> = listOf(
-        BroadcastSentViaContextDetector.ISSUE)
+    override fun getIssues(): List<Issue> = listOf(BroadcastSentViaContextDetector.ISSUE)
 
     @Test
     fun testSendBroadcast() {
-        lint().files(
-            TestFiles.java(
-                """
+        println(stubs.size)
+        lint()
+            .files(
+                TestFiles.java(
+                        """
                     package test.pkg;
                     import android.content.Context;
 
@@ -31,21 +48,25 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
+                    )
+                    .indented(),
+                *stubs
+            )
             .issues(BroadcastSentViaContextDetector.ISSUE)
             .run()
             .expectWarningCount(1)
             .expectContains(
-            "Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
-                    "Context, use com.android.systemui.broadcast.BroadcastSender instead.")
+                "Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
+                    "Context, use com.android.systemui.broadcast.BroadcastSender instead."
+            )
     }
 
     @Test
     fun testSendBroadcastAsUser() {
-        lint().files(
-            TestFiles.java(
-                """
+        lint()
+            .files(
+                TestFiles.java(
+                        """
                     package test.pkg;
                     import android.content.Context;
                     import android.os.UserHandle;
@@ -56,21 +77,26 @@
                           context.sendBroadcastAsUser(intent, UserHandle.ALL, "permission");
                         }
                     }
-                """).indented(),
-                *stubs)
+                """
+                    )
+                    .indented(),
+                *stubs
+            )
             .issues(BroadcastSentViaContextDetector.ISSUE)
             .run()
             .expectWarningCount(1)
             .expectContains(
-            "Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
-                    "Context, use com.android.systemui.broadcast.BroadcastSender instead.")
+                "Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
+                    "Context, use com.android.systemui.broadcast.BroadcastSender instead."
+            )
     }
 
     @Test
     fun testSendBroadcastInActivity() {
-        lint().files(
-            TestFiles.java(
-                """
+        lint()
+            .files(
+                TestFiles.java(
+                        """
                     package test.pkg;
                     import android.app.Activity;
                     import android.os.UserHandle;
@@ -82,21 +108,26 @@
                         }
 
                     }
-                """).indented(),
-                *stubs)
+                """
+                    )
+                    .indented(),
+                *stubs
+            )
             .issues(BroadcastSentViaContextDetector.ISSUE)
             .run()
             .expectWarningCount(1)
             .expectContains(
-            "Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
-                    "Context, use com.android.systemui.broadcast.BroadcastSender instead.")
+                "Please don't call sendBroadcast/sendBroadcastAsUser directly on " +
+                    "Context, use com.android.systemui.broadcast.BroadcastSender instead."
+            )
     }
 
     @Test
     fun testNoopIfNoCall() {
-        lint().files(
-            TestFiles.java(
-                """
+        lint()
+            .files(
+                TestFiles.java(
+                        """
                     package test.pkg;
                     import android.content.Context;
 
@@ -106,45 +137,15 @@
                           context.startActivity(intent);
                         }
                     }
-                """).indented(),
-                *stubs)
+                """
+                    )
+                    .indented(),
+                *stubs
+            )
             .issues(BroadcastSentViaContextDetector.ISSUE)
             .run()
             .expectClean()
     }
 
-    private val contextStub: TestFile = java(
-        """
-        package android.content;
-        import android.os.UserHandle;
-
-        public class Context {
-            public void sendBroadcast(Intent intent) {};
-            public void sendBroadcast(Intent intent, String receiverPermission) {};
-            public void sendBroadcastAsUser(Intent intent, UserHandle userHandle,
-                                                String permission) {};
-        }
-        """
-    )
-
-    private val activityStub: TestFile = java(
-        """
-        package android.app;
-        import android.content.Context;
-
-        public class Activity extends Context {}
-        """
-    )
-
-    private val userHandleStub: TestFile = java(
-        """
-        package android.os;
-
-        public enum UserHandle {
-            ALL
-        }
-        """
-    )
-
-    private val stubs = arrayOf(contextStub, activityStub, userHandleStub)
+    private val stubs = androidStubs
 }
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/GetMainLooperViaContextDetectorTest.kt
similarity index 64%
rename from packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt
rename to packages/SystemUI/checks/tests/com/android/internal/systemui/lint/GetMainLooperViaContextDetectorTest.kt
index ec761cd..c55f399 100644
--- a/packages/SystemUI/checks/tests/com/android/systemui/lint/GetMainLooperViaContextDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/GetMainLooperViaContextDetectorTest.kt
@@ -17,13 +17,13 @@
 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
 
+@Suppress("UnstableApiUsage")
 class GetMainLooperViaContextDetectorTest : LintDetectorTest() {
 
     override fun getDetector(): Detector = GetMainLooperViaContextDetector()
@@ -35,7 +35,8 @@
 
     @Test
     fun testGetMainThreadHandler() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -48,17 +49,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(GetMainLooperViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(GetMainLooperViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
     @Test
     fun testGetMainLooper() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -71,17 +75,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(GetMainLooperViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(GetMainLooperViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
     @Test
     fun testGetMainExecutor() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -94,42 +101,15 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(GetMainLooperViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(GetMainLooperViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
-    private val contextStub: TestFile = java(
-            """
-        package android.content;
-        import android.os.Handler;import android.os.Looper;import java.util.concurrent.Executor;
-
-        public class Context {
-            public Looper getMainLooper() { return null; };
-            public Executor getMainExecutor() { return null; };
-            public Handler getMainThreadHandler() { return null; };
-        }
-        """
-    )
-
-    private val looperStub: TestFile = java(
-            """
-        package android.os;
-
-        public class Looper {}
-        """
-    )
-
-    private val handlerStub: TestFile = java(
-            """
-        package android.os;
-
-        public class Handler {}
-        """
-    )
-
-    private val stubs = arrayOf(contextStub, looperStub, handlerStub)
+    private val stubs = androidStubs
 }
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/NonInjectedServiceDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/NonInjectedServiceDetectorTest.kt
new file mode 100644
index 0000000..6b9f88f
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/NonInjectedServiceDetectorTest.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.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+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
+
+@Suppress("UnstableApiUsage")
+class NonInjectedServiceDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = NonInjectedServiceDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+    override fun getIssues(): List<Issue> = listOf(NonInjectedServiceDetector.ISSUE)
+
+    @Test
+    fun testGetServiceWithString() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.content.Context;
+
+                        public class TestClass1 {
+                            public void getSystemServiceWithoutDagger(Context context) {
+                                context.getSystemService("user");
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(NonInjectedServiceDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains("Use @Inject to get the handle")
+    }
+
+    @Test
+    fun testGetServiceWithClass() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.content.Context;
+                        import android.os.UserManager;
+
+                        public class TestClass2 {
+                            public void getSystemServiceWithoutDagger(Context context) {
+                                context.getSystemService(UserManager.class);
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(NonInjectedServiceDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains("Use @Inject to get the handle")
+    }
+
+    private val stubs = androidStubs
+}
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
similarity index 60%
rename from packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
rename to packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
index 76c0519..802ceba 100644
--- a/packages/SystemUI/checks/tests/com/android/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/RegisterReceiverViaContextDetectorTest.kt
@@ -17,26 +17,26 @@
 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
 
+@Suppress("UnstableApiUsage")
 class RegisterReceiverViaContextDetectorTest : LintDetectorTest() {
 
     override fun getDetector(): Detector = RegisterReceiverViaContextDetector()
     override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
 
-    override fun getIssues(): List<Issue> = listOf(
-            RegisterReceiverViaContextDetector.ISSUE)
+    override fun getIssues(): List<Issue> = listOf(RegisterReceiverViaContextDetector.ISSUE)
 
     private val explanation = "BroadcastReceivers should be registered via BroadcastDispatcher."
 
     @Test
     fun testRegisterReceiver() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -51,17 +51,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(RegisterReceiverViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(RegisterReceiverViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
     @Test
     fun testRegisterReceiverAsUser() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -79,17 +82,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(RegisterReceiverViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(RegisterReceiverViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
     @Test
     fun testRegisterReceiverForAllUsers() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     package test.pkg;
@@ -107,65 +113,15 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(RegisterReceiverViaContextDetector.ISSUE)
-                .run()
-                .expectWarningCount(1)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(RegisterReceiverViaContextDetector.ISSUE)
+            .run()
+            .expectWarningCount(1)
+            .expectContains(explanation)
     }
 
-    private val contextStub: TestFile = java(
-            """
-        package android.content;
-        import android.os.Handler;
-        import android.os.UserHandle;
-
-        public class Context {
-            public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
-                int flags) {};
-            public void registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
-                IntentFilter filter, String broadcastPermission, Handler scheduler) {};
-            public void registerReceiverForAllUsers(BroadcastReceiver receiver, IntentFilter filter,
-                String broadcastPermission, Handler scheduler) {};
-        }
-        """
-    )
-
-    private val broadcastReceiverStub: TestFile = java(
-            """
-        package android.content;
-
-        public class BroadcastReceiver {}
-        """
-    )
-
-    private val intentFilterStub: TestFile = java(
-            """
-        package android.content;
-
-        public class IntentFilter {}
-        """
-    )
-
-    private val handlerStub: TestFile = java(
-            """
-        package android.os;
-
-        public class Handler {}
-        """
-    )
-
-    private val userHandleStub: TestFile = java(
-            """
-        package android.os;
-
-        public enum UserHandle {
-            ALL
-        }
-        """
-    )
-
-    private val stubs = arrayOf(contextStub, broadcastReceiverStub, intentFilterStub, handlerStub,
-            userHandleStub)
+    private val stubs = androidStubs
 }
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SlowUserQueryDetectorTest.kt
similarity index 74%
rename from packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
rename to packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SlowUserQueryDetectorTest.kt
index 2738f04..e265837 100644
--- a/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SlowUserQueryDetectorTest.kt
@@ -1,13 +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 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
 
+@Suppress("UnstableApiUsage")
 class SlowUserQueryDetectorTest : LintDetectorTest() {
 
     override fun getDetector(): Detector = SlowUserQueryDetector()
@@ -134,61 +150,5 @@
             .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)
+    private val stubs = androidStubs
 }
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt
similarity index 70%
rename from packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt
rename to packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt
index 890f2b8..fd6ab09 100644
--- a/packages/SystemUI/checks/tests/com/android/systemui/lint/SoftwareBitmapDetectorTest.kt
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt
@@ -17,7 +17,6 @@
 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
@@ -36,7 +35,8 @@
 
     @Test
     fun testSoftwareBitmap() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     import android.graphics.Bitmap;
@@ -48,17 +48,20 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(SoftwareBitmapDetector.ISSUE)
-                .run()
-                .expectWarningCount(2)
-                .expectContains(explanation)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(SoftwareBitmapDetector.ISSUE)
+            .run()
+            .expectWarningCount(2)
+            .expectContains(explanation)
     }
 
     @Test
     fun testHardwareBitmap() {
-        lint().files(
+        lint()
+            .files(
                 TestFiles.java(
                         """
                     import android.graphics.Bitmap;
@@ -69,29 +72,14 @@
                         }
                     }
                 """
-                ).indented(),
-                *stubs)
-                .issues(SoftwareBitmapDetector.ISSUE)
-                .run()
-                .expectWarningCount(0)
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(SoftwareBitmapDetector.ISSUE)
+            .run()
+            .expectWarningCount(0)
     }
 
-    private val bitmapStub: TestFile = java(
-            """
-        package android.graphics;
-
-        public class Bitmap {
-            public enum Config {
-                ARGB_8888,
-                RGB_565,
-                HARDWARE
-            }
-            public static Bitmap createBitmap(int width, int height, Config config) {
-                return null;
-            }
-        }
-        """
-    )
-
-    private val stubs = arrayOf(bitmapStub)
+    private val stubs = androidStubs
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
index 3175dcf..4d94bab 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/user/ui/compose/UserSwitcherScreen.kt
@@ -17,8 +17,6 @@
 
 package com.android.systemui.user.ui.compose
 
-import android.graphics.Bitmap
-import android.graphics.Canvas
 import android.graphics.drawable.Drawable
 import androidx.appcompat.content.res.AppCompatResources
 import androidx.compose.foundation.Image
@@ -50,10 +48,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.alpha
 import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.asImageBitmap
 import androidx.compose.ui.graphics.painter.ColorPainter
-import androidx.compose.ui.graphics.toArgb
 import androidx.compose.ui.platform.LocalConfiguration
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.platform.LocalDensity
@@ -62,6 +58,7 @@
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.toBitmap
 import com.android.systemui.common.ui.compose.load
 import com.android.systemui.compose.SysUiOutlinedButton
 import com.android.systemui.compose.SysUiTextButton
@@ -356,10 +353,11 @@
         remember(viewModel.iconResourceId) {
             val drawable =
                 checkNotNull(AppCompatResources.getDrawable(context, viewModel.iconResourceId))
+            val size = with(density) { 20.dp.toPx() }.toInt()
             drawable
                 .toBitmap(
-                    size = with(density) { 20.dp.toPx() }.toInt(),
-                    tintColor = Color.White,
+                    width = size,
+                    height = size,
                 )
                 .asImageBitmap()
         }
@@ -392,32 +390,3 @@
                 ),
     )
 }
-
-/**
- * Converts the [Drawable] to a [Bitmap].
- *
- * Note that this is a relatively memory-heavy operation as it allocates a whole bitmap and draws
- * the `Drawable` onto it. Use sparingly and with care.
- */
-private fun Drawable.toBitmap(
-    size: Int? = null,
-    tintColor: Color? = null,
-): Bitmap {
-    val bitmap =
-        if (intrinsicWidth <= 0 || intrinsicHeight <= 0) {
-            Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
-        } else {
-            Bitmap.createBitmap(
-                size ?: intrinsicWidth,
-                size ?: intrinsicHeight,
-                Bitmap.Config.ARGB_8888
-            )
-        }
-    val canvas = Canvas(bitmap)
-    setBounds(0, 0, canvas.width, canvas.height)
-    if (tintColor != null) {
-        setTint(tintColor.toArgb())
-    }
-    draw(canvas)
-    return bitmap
-}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
index 01e5d86..1e74c3d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockProviderPlugin.kt
@@ -39,19 +39,19 @@
     fun getClocks(): List<ClockMetadata>
 
     /** Initializes and returns the target clock design */
-    fun createClock(id: ClockId): Clock
+    fun createClock(id: ClockId): ClockController
 
     /** A static thumbnail for rendering in some examples */
     fun getClockThumbnail(id: ClockId): Drawable?
 }
 
 /** Interface for controlling an active clock */
-interface Clock {
+interface ClockController {
     /** A small version of the clock, appropriate for smaller viewports */
-    val smallClock: View
+    val smallClock: ClockFaceController
 
     /** A large version of the clock, appropriate when a bigger viewport is available */
-    val largeClock: View
+    val largeClock: ClockFaceController
 
     /** Events that clocks may need to respond to */
     val events: ClockEvents
@@ -61,7 +61,7 @@
 
     /** Initializes various rendering parameters. If never called, provides reasonable defaults. */
     fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
-        events.onColorPaletteChanged(resources, true, true)
+        events.onColorPaletteChanged(resources)
         animations.doze(dozeFraction)
         animations.fold(foldFraction)
         events.onTimeTick()
@@ -71,10 +71,19 @@
     fun dump(pw: PrintWriter) { }
 }
 
+/** Interface for a specific clock face version rendered by the clock */
+interface ClockFaceController {
+    /** View that renders the clock face */
+    val view: View
+
+    /** Events specific to this clock face */
+    val events: ClockFaceEvents
+}
+
 /** Events that should call when various rendering parameters change */
 interface ClockEvents {
     /** Call every time tick */
-    fun onTimeTick()
+    fun onTimeTick() { }
 
     /** Call whenever timezone changes */
     fun onTimeZoneChanged(timeZone: TimeZone) { }
@@ -89,11 +98,7 @@
     fun onFontSettingChanged() { }
 
     /** Call whenever the color palette should update */
-    fun onColorPaletteChanged(
-            resources: Resources,
-            smallClockIsDark: Boolean,
-            largeClockIsDark: Boolean
-    ) { }
+    fun onColorPaletteChanged(resources: Resources) { }
 }
 
 /** Methods which trigger various clock animations */
@@ -111,6 +116,12 @@
     fun charge() { }
 }
 
+/** Events that have specific data about the related face */
+interface ClockFaceEvents {
+    /** Region Darkness specific to the clock face */
+    fun onRegionDarknessChanged(isDark: Boolean) { }
+}
+
 /** Some data about a clock design */
 data class ClockMetadata(
     val clockId: ClockId,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
index 1237259..5f6f11c 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
@@ -61,5 +61,12 @@
 
         /** Indicates that the gesture was cancelled and the system should not go back. */
         void cancelBack();
+
+        /**
+         * Indicates if back will be triggered if committed in current state.
+         *
+         * @param triggerBack if back will be triggered in current state.
+         */
+        void setTriggerBack(boolean triggerBack);
     }
 }
diff --git a/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
index 6986961..9d063e9 100644
--- a/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
+++ b/packages/SystemUI/res-keyguard/drawable/bouncer_user_switcher_header_bg.xml
@@ -21,11 +21,12 @@
             android:paddingEnd="0dp">
     <item>
         <shape android:shape="rectangle">
-          <solid android:color="?androidprv:attr/colorSurface" />
+          <solid android:color="?androidprv:attr/colorSurfaceHighlight" />
             <corners android:radius="32dp" />
         </shape>
     </item>
     <item
+        android:id="@+id/user_switcher_key_down"
         android:drawable="@drawable/ic_ksh_key_down"
         android:gravity="end|center_vertical"
         android:width="32dp"
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions.xml b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
index 1ce106e..2261ae8 100644
--- a/packages/SystemUI/res-keyguard/layout/footer_actions.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
@@ -46,7 +46,7 @@
         >
 
         <com.android.systemui.statusbar.phone.MultiUserSwitch
-            android:id="@+id/multi_user_switch"
+            android:id="@id/multi_user_switch"
             android:layout_width="@dimen/qs_footer_action_button_size"
             android:layout_height="@dimen/qs_footer_action_button_size"
             android:background="@drawable/qs_footer_action_circle"
@@ -61,7 +61,7 @@
         </com.android.systemui.statusbar.phone.MultiUserSwitch>
 
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-            android:id="@+id/settings_button_container"
+            android:id="@id/settings_button_container"
             android:layout_width="@dimen/qs_footer_action_button_size"
             android:layout_height="@dimen/qs_footer_action_button_size"
             android:background="@drawable/qs_footer_action_circle"
@@ -85,7 +85,7 @@
         </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:id="@+id/pm_lite"
+            android:id="@id/pm_lite"
             android:layout_width="@dimen/qs_footer_action_button_size"
             android:layout_height="@dimen/qs_footer_action_button_size"
             android:background="@drawable/qs_footer_action_circle_color"
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
new file mode 100644
index 0000000..29832a0
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_inner.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto" >
+
+    <com.android.keyguard.AlphaOptimizedLinearLayout
+        android:id="@+id/mobile_group"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="center_vertical"
+        android:orientation="horizontal" >
+
+        <FrameLayout
+            android:id="@+id/inout_container"
+            android:layout_height="17dp"
+            android:layout_width="wrap_content"
+            android:layout_gravity="center_vertical">
+            <ImageView
+                android:id="@+id/mobile_in"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:src="@drawable/ic_activity_down"
+                android:visibility="gone"
+                android:paddingEnd="2dp"
+                />
+            <ImageView
+                android:id="@+id/mobile_out"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:src="@drawable/ic_activity_up"
+                android:paddingEnd="2dp"
+                android:visibility="gone"
+                />
+        </FrameLayout>
+        <ImageView
+            android:id="@+id/mobile_type"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:paddingStart="2.5dp"
+            android:paddingEnd="1dp"
+            android:visibility="gone" />
+        <Space
+            android:id="@+id/mobile_roaming_space"
+            android:layout_height="match_parent"
+            android:layout_width="@dimen/roaming_icon_start_padding"
+            android:visibility="gone"
+            />
+        <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical">
+            <com.android.systemui.statusbar.AnimatedImageView
+                android:id="@+id/mobile_signal"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                systemui:hasOverlappingRendering="false"
+                />
+            <ImageView
+                android:id="@+id/mobile_roaming"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:src="@drawable/stat_sys_roaming"
+                android:contentDescription="@string/data_connection_roaming"
+                android:visibility="gone" />
+        </FrameLayout>
+        <ImageView
+            android:id="@+id/mobile_roaming_large"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@drawable/stat_sys_roaming_large"
+            android:contentDescription="@string/data_connection_roaming"
+            android:visibility="gone" />
+    </com.android.keyguard.AlphaOptimizedLinearLayout>
+</merge>
diff --git a/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_new.xml b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_new.xml
new file mode 100644
index 0000000..1b38fd2
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/status_bar_mobile_signal_group_new.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2022, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/mobile_combo"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:gravity="center_vertical" >
+
+    <include layout="@layout/status_bar_mobile_signal_group_inner" />
+
+</com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView>
+
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index 62379f8..45dadc1 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -29,7 +29,7 @@
     <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>
+    <string name="keyguard_plugged_in_charging_slowly" msgid="217655355424210">"<xliff:g id="PERCENTAGE">%s</xliff:g> • Recharge lente"</string>
     <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>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index cad7159..5ee67d91 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -68,9 +68,9 @@
     <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="190984061975729494">"Ai introdus incorect parola de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4252405904570284368">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. \n\nÎncearcă din nou peste <xliff:g id="NUMBER_1">%2$d</xliff:g> secunde."</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="8047350661459040581">"Codul PIN pentru cardul SIM este incorect. Contactează operatorul pentru a debloca dispozitivul."</string>
-    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{Codul PIN pentru cardul SIM este incorect. V-a mai rămas # încercare, după care va trebui să contactați operatorul pentru a vă debloca dispozitivul.}few{Codul PIN pentru cardul SIM este incorect. V-au mai rămas # încercări. }other{Codul PIN pentru cardul SIM este incorect. V-au mai rămas # de încercări. }}"</string>
+    <string name="kg_password_wrong_pin_code" msgid="5629415765976820357">"{count,plural, =1{PIN-ul cardului SIM e incorect. Ți-a mai rămas # încercare, după care va trebui să contactezi operatorul pentru a debloca dispozitivul.}few{PIN-ul cardului SIM e incorect. Ți-au mai rămas # încercări. }other{PIN-ul cardului SIM e incorect. Ți-au mai rămas # de încercări. }}"</string>
     <string name="kg_password_wrong_puk_code_dead" msgid="3698285357028468617">"Cardul SIM nu poate fi utilizat. Contactează operatorul."</string>
-    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Codul PUK pentru cardul SIM este incorect. V-a mai rămas # încercare până când cardul SIM va deveni inutilizabil definitiv.}few{Codul PUK pentru cardul SIM este incorect. V-au mai rămas # încercări până când cardul SIM va deveni inutilizabil definitiv.}other{Codul PUK pentru cardul SIM este incorect. V-au mai rămas # de încercări până când cardul SIM va deveni inutilizabil definitiv.}}"</string>
+    <string name="kg_password_wrong_puk_code" msgid="6820515467645087827">"{count,plural, =1{Codul PUK pentru cardul SIM e incorect. Ți-a mai rămas # încercare până când cardul SIM va deveni inutilizabil definitiv.}few{Codul PUK pentru cardul SIM e incorect. Ți-au mai rămas # încercări până când cardul SIM va deveni inutilizabil definitiv.}other{Codul PUK pentru cardul SIM e incorect. Ți-au mai rămas # de încercări până când cardul SIM va deveni inutilizabil definitiv.}}"</string>
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Deblocarea cu ajutorul codului PIN pentru cardul SIM nu a reușit!"</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Deblocarea cu ajutorul codului PUK pentru cardul SIM nu a reușit!"</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Schimbă metoda de introducere"</string>
@@ -84,9 +84,9 @@
     <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"Dispozitiv blocat de administrator"</string>
     <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"Dispozitivul a fost blocat manual"</string>
     <string name="kg_face_not_recognized" msgid="7903950626744419160">"Nu este recunoscut"</string>
-    <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Pentru Deblocare facială, activați accesul la cameră"</string>
-    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introduceți codul PIN pentru cardul SIM. V-a mai rămas # încercare, după care va trebui să contactați operatorul pentru a vă debloca dispozitivul.}few{Introduceți codul PIN al cardului SIM. V-au rămas # încercări.}other{Introduceți codul PIN al cardului SIM. V-au rămas # de încercări.}}"</string>
-    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-a mai rămas # încercare până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.}few{Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas # încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.}other{Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas # de încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.}}"</string>
+    <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"Pentru Deblocare facială, activează accesul la cameră"</string>
+    <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{Introdu PIN-ul cardului SIM. Ți-a mai rămas # încercare, după care va trebui să contactezi operatorul pentru a debloca dispozitivul.}few{Introdu PIN-ul cardului SIM. Ți-au rămas # încercări.}other{Introdu PIN-ul cardului SIM. Ți-au rămas # de încercări.}}"</string>
+    <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{Cardul SIM e acum dezactivat. Introdu codul PUK pentru a continua. Ți-a mai rămas # încercare până când cardul SIM va deveni inutilizabil definitiv. Contactează operatorul pentru detalii.}few{Cardul SIM e acum dezactivat. Introdu codul PUK pentru a continua. Ți-au mai rămas # încercări până când cardul SIM va deveni inutilizabil definitiv. Contactează operatorul pentru detalii.}other{Cardul SIM e acum dezactivat. Introdu codul PUK pentru a continua. Ți-au mai rămas # de încercări până când cardul SIM va deveni inutilizabil definitiv. Contactează operatorul pentru detalii.}}"</string>
     <string name="clock_title_default" msgid="6342735240617459864">"Prestabilit"</string>
     <string name="clock_title_bubble" msgid="2204559396790593213">"Balon"</string>
     <string name="clock_title_analog" msgid="8409262532900918273">"Analogic"</string>
diff --git a/packages/SystemUI/res-keyguard/values/ids.xml b/packages/SystemUI/res-keyguard/values/ids.xml
new file mode 100644
index 0000000..0dff4ff
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/values/ids.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>
+    <item type="id" name="header_footer_views_added_tag_key" />
+</resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index a1d1266..b86929e 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -25,7 +25,7 @@
     </style>
     <style name="Keyguard.TextView.EmergencyButton" parent="Theme.SystemUI">
         <item name="android:textColor">?androidprv:attr/textColorOnAccent</item>
-        <item name="android:textSize">14dp</item>
+        <item name="android:textSize">14sp</item>
         <item name="android:background">@drawable/kg_emergency_button_background</item>
         <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
         <item name="android:paddingLeft">12dp</item>
diff --git a/packages/SystemUI/res-product/values-ro/strings.xml b/packages/SystemUI/res-product/values-ro/strings.xml
index 807ebfe0..471f01e 100644
--- a/packages/SystemUI/res-product/values-ro/strings.xml
+++ b/packages/SystemUI/res-product/values-ro/strings.xml
@@ -19,16 +19,16 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="dock_alignment_slow_charging" product="default" msgid="6997633396534416792">"Repoziționați telefonul pentru încărcare mai rapidă"</string>
-    <string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"Repoziționați telefonul pentru încărcarea wireless"</string>
+    <string name="dock_alignment_slow_charging" product="default" msgid="6997633396534416792">"Repoziționează telefonul pentru încărcare mai rapidă"</string>
+    <string name="dock_alignment_not_charging" product="default" msgid="3980752926226749808">"Repoziționează telefonul pentru încărcarea wireless"</string>
     <string name="inattentive_sleep_warning_message" product="tv" msgid="6844464574089665063">"Dispozitivul Android TV se va opri în curând. Apasă un buton pentru a-l menține pornit."</string>
     <string name="inattentive_sleep_warning_message" product="default" msgid="5693904520452332224">"Dispozitivul se va opri în curând. Apasă pentru a-l menține pornit."</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="5018086454277963787">"Nu există card SIM în tabletă."</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="7053347843877341391">"Nu există card SIM în telefon."</string>
     <string name="kg_invalid_confirm_pin_hint" product="default" msgid="6278551068943958651">"Codurile PIN nu coincid"</string>
-    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Ați efectuat <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
+    <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="302165994845009232">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, tableta va fi resetată, iar toate datele vor fi șterse."</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="2594813176164266847">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Ați efectuat <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele acesteia vor fi șterse."</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="8710104080409538587">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Această tabletă va fi resetată, iar toate datele vor fi șterse."</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="6381835450014881813">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Acest telefon va fi resetat, iar toate datele acestuia vor fi șterse."</string>
     <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="7325071812832605911">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a tabletei. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
     <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="8110939900089863103">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, acest utilizator va fi eliminat, iar toate datele utilizatorului vor fi șterse."</string>
@@ -38,8 +38,8 @@
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="3280816298678433681">"Ai făcut <xliff:g id="NUMBER_0">%1$d</xliff:g> încercări incorecte de deblocare a telefonului. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4417100487251371559">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a tabletei. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"Ai făcut <xliff:g id="NUMBER">%d</xliff:g> încercări incorecte de deblocare a telefonului. Profilul de serviciu va fi eliminat, iar toate datele profilului vor fi șterse."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați tableta cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi tableta cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"Ai desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, ți se va solicita să deblochezi telefonul cu ajutorul unui cont de e-mail.\n\n Încearcă din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
     <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"Deblochează telefonul pentru mai multe opțiuni"</string>
     <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"Deblochează tableta pentru mai multe opțiuni"</string>
     <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"Deblochează dispozitivul pentru mai multe opțiuni"</string>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 8df8c49..6120863 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -59,7 +59,7 @@
 
     </LinearLayout>
 
-    <ImageView
+    <com.android.systemui.common.ui.view.LaunchableImageView
         android:id="@+id/start_button"
         android:layout_height="@dimen/keyguard_affordance_fixed_height"
         android:layout_width="@dimen/keyguard_affordance_fixed_width"
@@ -71,7 +71,7 @@
         android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
         android:visibility="gone" />
 
-    <ImageView
+    <com.android.systemui.common.ui.view.LaunchableImageView
         android:id="@+id/end_button"
         android:layout_height="@dimen/keyguard_affordance_fixed_height"
         android:layout_width="@dimen/keyguard_affordance_fixed_width"
diff --git a/packages/SystemUI/res/layout/media_projection_app_selector.xml b/packages/SystemUI/res/layout/media_projection_app_selector.xml
index 226bc6a..e474938 100644
--- a/packages/SystemUI/res/layout/media_projection_app_selector.xml
+++ b/packages/SystemUI/res/layout/media_projection_app_selector.xml
@@ -49,6 +49,8 @@
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:textAppearance="?android:attr/textAppearanceLarge"
+            android:focusable="false"
+            android:clickable="false"
             android:gravity="center"
             android:paddingBottom="@*android:dimen/chooser_view_spacing"
             android:paddingLeft="24dp"
diff --git a/packages/SystemUI/res/layout/media_projection_recent_tasks.xml b/packages/SystemUI/res/layout/media_projection_recent_tasks.xml
index a2b3c40..31baf26 100644
--- a/packages/SystemUI/res/layout/media_projection_recent_tasks.xml
+++ b/packages/SystemUI/res/layout/media_projection_recent_tasks.xml
@@ -23,8 +23,9 @@
     >
 
     <FrameLayout
+        android:id="@+id/media_projection_recent_tasks_container"
         android:layout_width="match_parent"
-        android:layout_height="256dp">
+        android:layout_height="wrap_content">
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/media_projection_recent_tasks_recycler"
diff --git a/packages/SystemUI/res/layout/media_projection_task_item.xml b/packages/SystemUI/res/layout/media_projection_task_item.xml
index 75f73cd..cfa586f 100644
--- a/packages/SystemUI/res/layout/media_projection_task_item.xml
+++ b/packages/SystemUI/res/layout/media_projection_task_item.xml
@@ -18,7 +18,9 @@
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:gravity="center"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:clickable="true"
+    >
 
     <ImageView
         android:id="@+id/task_icon"
@@ -27,12 +29,12 @@
         android:layout_margin="8dp"
         android:importantForAccessibility="no" />
 
-    <!-- TODO(b/240924926) use a custom view that will handle thumbnail cropping correctly -->
-    <!-- TODO(b/240924926) dynamically change the view size based on the screen size -->
-    <ImageView
+    <!-- This view size will be calculated in runtime -->
+    <com.android.systemui.mediaprojection.appselector.view.MediaProjectionTaskView
         android:id="@+id/task_thumbnail"
-        android:layout_width="100dp"
-        android:layout_height="216dp"
-        android:scaleType="centerCrop"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:clickable="false"
+        android:focusable="false"
         />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/media_ttt_chip.xml b/packages/SystemUI/res/layout/media_ttt_chip.xml
index d886806..ae8e38e 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip.xml
@@ -16,7 +16,7 @@
 <!-- Wrap in a frame layout so that we can update the margins on the inner layout. (Since this view
      is the root view of a window, we cannot change the root view's margins.) -->
 <!-- Alphas start as 0 because the view will be animated in. -->
-<FrameLayout
+<com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/media_ttt_sender_chip"
@@ -97,4 +97,4 @@
             />
 
     </LinearLayout>
-</FrameLayout>
+</com.android.systemui.media.taptotransfer.sender.MediaTttChipRootView>
diff --git a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
index e079fd3..21d12c2 100644
--- a/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
+++ b/packages/SystemUI/res/layout/media_ttt_chip_receiver.xml
@@ -29,6 +29,7 @@
 
     <com.android.internal.widget.CachingIconView
         android:id="@+id/app_icon"
+        android:background="@drawable/media_ttt_chip_background_receiver"
         android:layout_width="@dimen/media_ttt_icon_size_receiver"
         android:layout_height="@dimen/media_ttt_icon_size_receiver"
         android:layout_gravity="center|bottom"
diff --git a/packages/SystemUI/res/layout/screenshot.xml b/packages/SystemUI/res/layout/screenshot.xml
index c29e11b..c134c8e 100644
--- a/packages/SystemUI/res/layout/screenshot.xml
+++ b/packages/SystemUI/res/layout/screenshot.xml
@@ -35,12 +35,6 @@
         android:visibility="gone"
         android:elevation="7dp"
         android:src="@android:color/white"/>
-    <com.android.systemui.screenshot.ScreenshotSelectorView
-        android:id="@+id/screenshot_selector"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:visibility="gone"
-        android:pointerIcon="crosshair"/>
     <include layout="@layout/screenshot_static"
              android:id="@+id/screenshot_static"/>
 </com.android.systemui.screenshot.ScreenshotView>
diff --git a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
index 10d49b3..d6c63eb 100644
--- a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -18,80 +18,12 @@
 -->
 <com.android.systemui.statusbar.StatusBarMobileView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:id="@+id/mobile_combo"
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
     android:gravity="center_vertical" >
 
-    <com.android.keyguard.AlphaOptimizedLinearLayout
-        android:id="@+id/mobile_group"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:gravity="center_vertical"
-        android:orientation="horizontal" >
+    <include layout="@layout/status_bar_mobile_signal_group_inner" />
 
-        <FrameLayout
-            android:id="@+id/inout_container"
-            android:layout_height="17dp"
-            android:layout_width="wrap_content"
-            android:layout_gravity="center_vertical">
-            <ImageView
-                android:id="@+id/mobile_in"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:src="@drawable/ic_activity_down"
-                android:visibility="gone"
-                android:paddingEnd="2dp"
-            />
-            <ImageView
-                android:id="@+id/mobile_out"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                android:src="@drawable/ic_activity_up"
-                android:paddingEnd="2dp"
-                android:visibility="gone"
-            />
-        </FrameLayout>
-        <ImageView
-            android:id="@+id/mobile_type"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:paddingStart="2.5dp"
-            android:paddingEnd="1dp"
-            android:visibility="gone" />
-        <Space
-            android:id="@+id/mobile_roaming_space"
-            android:layout_height="match_parent"
-            android:layout_width="@dimen/roaming_icon_start_padding"
-            android:visibility="gone"
-        />
-        <FrameLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical">
-            <com.android.systemui.statusbar.AnimatedImageView
-                android:id="@+id/mobile_signal"
-                android:layout_height="wrap_content"
-                android:layout_width="wrap_content"
-                systemui:hasOverlappingRendering="false"
-            />
-            <ImageView
-                android:id="@+id/mobile_roaming"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:src="@drawable/stat_sys_roaming"
-                android:contentDescription="@string/data_connection_roaming"
-                android:visibility="gone" />
-        </FrameLayout>
-        <ImageView
-            android:id="@+id/mobile_roaming_large"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/stat_sys_roaming_large"
-            android:contentDescription="@string/data_connection_roaming"
-            android:visibility="gone" />
-    </com.android.keyguard.AlphaOptimizedLinearLayout>
 </com.android.systemui.statusbar.StatusBarMobileView>
 
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 5771547..167885e 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Deurlopende kennisgewing vir \'n skermopnamesessie"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Begin opname?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Terwyl dit opneem, kan die Android-stelsel enige sensitiewe inligting wat op jou skerm sigbaar is of wat op jou toestel gespeel word, vasvang. Dit sluit wagwoorde, betalinginligting, foto\'s, boodskappe en oudio in."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Neem hele skerm op"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Neem ’n enkele program op"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Terwyl jy opneem, het Android toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Terwyl jy ’n program opneem, het Android toegang tot enigiets wat in daardie program gewys of gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Begin opneem"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Neem oudio op"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Toesteloudio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Klank vanaf jou toestel, soos musiek, oproepe en luitone"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Die diens wat hierdie funksie verskaf, sal toegang hê tot al die inligting wat op jou skerm sigbaar is of wat op jou toestel gespeel word terwyl dit opneem of uitsaai. Dit sluit in inligting soos wagwoorde, betalingbesonderhede, foto\'s, boodskappe en oudio wat jy speel."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Begin opneem of uitsaai?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Begin opneem of uitsaai met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Laat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toe om te deel of op te neem?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Hele skerm"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"’n Enkele program"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Wanneer jy deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat op jou skerm sigbaar is of op jou toestel gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Wanneer jy ’n program deel, opneem of uitsaai, het <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot enigiets wat in daardie program sigbaar is of daarin gespeel word. Wees dus versigtig met wagwoorde, betalingbesonderhede, boodskappe of ander sensitiewe inligting."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Gaan voort"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deel of neem ’n program op"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Vee alles uit"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Bestuur"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Geskiedenis"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0f6410a..f07f10d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ለአንድ የማያ ገጽ ቀረጻ ክፍለ-ጊዜ በመካሄድ ያለ ማሳወቂያ"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"መቅረጽ ይጀመር?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"እየቀረጹ ሳለ የAndroid ስርዓት በማያ ገጽዎ ላይ የሚታይ ወይም በመሣሪያዎ ላይ የሚጫወት ማንኛውም ሚስጥራዊነት ያለው መረጃን መያዝ ይችላል። ይህ የይለፍ ቃላትን፣ የክፍያ መረጃን፣ ፎቶዎችን፣ መልዕክቶችን እና ኦዲዮን ያካትታል።"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ኦዲዮን ቅረጽ"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"የመሣሪያ ኦዲዮ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"እንደ ሙዚቃ፣ ጥሪዎች እና የጥሪ ቅላጼዎች ያሉ የመሣሪያዎ ድምጽ"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ይህን ተግባር የሚያቀርበው አገልግሎት በእርስዎ ማያ ገጽ ላይ ያለን ወይም በእርስዎ መሣሪያ ላይ በመጫወት ላይ ያለን ሁሉንም መረጃ በቀረጻ ወይም casting ላይ እያለ መዳረሻ ይኖረዋል። ይህ እንደ የይለፍ ቃላት፣ የክፍያ ዝርዝሮች፣ ፎቶዎች፣ መልዕክቶች እና እርስዎ የሚጫውቱት ኦዲዮን የመሳሰለ መረጃን ያካትታል።"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ቀረጻ ወይም cast ማድረግ ይጀምር?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"ከ<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ጋር ቀረጻ ወይም casting ይጀምር?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ሁሉንም አጽዳ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ያቀናብሩ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ታሪክ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 2724aee..732c2e6 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"إشعار مستمر لجلسة تسجيل شاشة"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"هل تريد بدء التسجيل؟"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"‏أثناء التسجيل، يمكن أن يسجّل نظام Android أي معلومات حساسة مرئية على شاشتك أو يتم تشغيلها على جهازك. ويشمل ذلك كلمات المرور ومعلومات الدفع والصور والرسائل والمقاطع الصوتية."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"تسجيل الصوت"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"صوت الجهاز"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"الصوت من جهازك، مثلاً الموسيقى والمكالمات ونغمات الرنين"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ستتمكن الخدمة التي تقدّم هذه الوظيفة من الوصول إلى كل المعلومات المرئية لك على الشاشة أو التي يتم تشغيلها على جهازك أثناء التسجيل أو الإرسال. ويشمل ذلك معلومات مثل كلمات المرور وتفاصيل الدفع والصور والرسائل والمقاطع الصوتية التي تشغِّلها."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"هل تريد بدء التسجيل أو الإرسال؟"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"هل تريد بدء التسجيل أو الإرسال باستخدام <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>؟"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"محو الكل"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"إدارة"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"السجلّ"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index bc4236c..c2f8e43 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -32,13 +32,13 @@
     <string name="battery_saver_start_action" msgid="8353766979886287140">"অন কৰক"</string>
     <string name="battery_saver_dismiss_action" msgid="7199342621040014738">"নালাগে, ধন্যবাদ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
-    <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ত প্ৰৱেশ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক অনুমতি দিবনে?"</string>
+    <string name="usb_device_permission_prompt" msgid="4414719028369181772">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> এক্সেছ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক অনুমতি দিবনে?"</string>
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_DEVICE">%2$s</xliff:g> এক্সেছ কৰিবলৈ অনুমতি দিবনে?\nএই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
     <string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_DEVICE">%2$s</xliff:g> এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
     <string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> নিয়ন্ত্ৰণ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g> খুলিবনে?"</string>
     <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"এই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে। এইটো ডিভাইচৰ সৈতে <xliff:g id="APPLICATION">%1$s</xliff:g> ব্যৱহাৰ কৰিলে কল, জাননী আৰু এলাৰ্ম শুনাটো অৱৰুদ্ধ হ’ব পাৰে।"</string>
     <string name="usb_audio_device_prompt" msgid="7944987408206252949">"এইটো ডিভাইচৰ সৈতে <xliff:g id="APPLICATION">%1$s</xliff:g> ব্যৱহাৰ কৰিলে কল, জাননী আৰু এলাৰ্ম শুনাটো অৱৰুদ্ধ হ’ব পাৰে।"</string>
-    <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ত প্ৰৱেশ কৰিবলৈ অনুমতি দিবনে?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"<xliff:g id="APPLICATION">%1$s</xliff:g>ক <xliff:g id="USB_ACCESSORY">%2$s</xliff:g> এক্সেছ কৰিবলৈ অনুমতি দিবনে?"</string>
     <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"<xliff:g id="USB_DEVICE">%2$s</xliff:g>ক ব্যৱহাৰ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক খোলেনে?"</string>
     <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"<xliff:g id="USB_DEVICE">%2$s</xliff:g> ব্যৱহাৰ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক খুলিবনে?\nএই এপ্‌টোক ৰেকর্ড কৰাৰ অনুমতি দিয়া হোৱা নাই কিন্তু ই এই ইউএছবি ডিভাইচটোৰ জৰিয়তে অডিঅ\' ৰেকর্ড কৰিব পাৰে।"</string>
     <string name="usb_accessory_confirm_prompt" msgid="5728408382798643421">"<xliff:g id="USB_ACCESSORY">%2$s</xliff:g>ক ব্যৱহাৰ কৰিবলৈ <xliff:g id="APPLICATION">%1$s</xliff:g>ক খোলেনে?"</string>
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রীন ৰেকৰ্ডিং ছেশ্বন চলি থকা সময়ত পোৱা জাননী"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ৰেকৰ্ড কৰা আৰম্ভ কৰিবনে?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ৰেকৰ্ড কৰি থাকোঁতে, Android Systemএ আপোনাৰ স্ক্রীনত দৃশ্যমান হোৱা অথবা আপোনাৰ ডিভাইচত প্লে’ হৈ থকা যিকোনো সংবেনদশীল তথ্য কেপচাৰ কৰিব পাৰে। এইটোত পাছৱর্ড, পৰিশোধৰ তথ্য, ফট’, বার্তাসমূহ আৰু অডিঅ’ অন্তর্ভুক্ত হয়।"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"অডিঅ’ ৰেকৰ্ড কৰক"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ডিভাইচৰ অডিঅ’"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"সংগীত, কল আৰু ৰিংট’নসমূহৰ দৰে আপোনাৰ ডিভাইচৰ পৰা কেপচাৰ কৰিব পৰা ধ্বনি"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"এই সুবিধাটো প্ৰদান কৰা সেৱাটোৱে আপোনাৰ স্ক্ৰীনত দৃশ্যমান হোৱা অথবা ৰেকর্ডিং অথবা কাষ্টিঙৰ সময়ত আপোনাৰ ডিভাইচত প্লে\' কৰা আটাইবোৰ তথ্যলৈ এক্সেছ পাব। এইটোত পাছৱর্ড, পৰিশোধৰ সবিশেষ, ফট\', বার্তাসমূহ আৰু আপুনি প্লে\' কৰা অডিঅ\'ৰ দৰে তথ্য অন্তর্ভুক্ত হয়।"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ৰ জৰিয়তে ৰেকর্ডিং অথবা কাষ্টিং আৰম্ভ কৰিবনে ?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"আটাইবোৰ মচক"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index f91ad01..0beb0ba 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekranın video çəkimi ərzində silinməyən bildiriş"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Yazmağa başlanılsın?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Ekranda görünən və ya cihazda oxudulan şəxsi məlumat (parol, bank hesabı, mesaj, fotoşəkil və sair) videoyazıya düşə bilər."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Bütün ekranı qeydə alın"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Bir tətbiqi qeydə alın"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Qeydə aldığınız zaman Android ekranınızda görünən və ya cihazınızda oxudulan hər şeyə giriş edə bilir. Odur ki, parollar, ödəniş detalları, mesajlar və ya digər həssas məlumatlarla bağlı diqqətli olun."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Tətbiqi qeydə aldığınız zaman Android həmin tətbiqdə göstərilən və ya oxudulan hər şeyə giriş edə bilir. Odur ki, parollar, ödəniş detalları, mesajlar və ya digər həssas məlumatlarla bağlı diqqətli olun."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Qeydə almağa başlayın"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Audio yazın"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Cihaz audiosu"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Cihazınızdan gələn musiqi, zənglər və zəng melodiyaları kimi səslər"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Bu funksiyanı təmin edən xidmətin yazma və ya yayım zamanı ekranda görünən və ya cihazdan oxudulan bütün bilgilərə girişi olacaq. Buraya parollar, ödəniş detalları, fotolar, mesajlar və oxudulan audio kimi məlumatlar daxildir."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Yazma və ya yayımlama başladılsın?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilə yazma və ya yayımlama başladılsın?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tətbiqinə paylaşmaq və ya qeydə almaq üçün icazə verilsin?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Bütün ekran"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Vahid tətbiq"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Paylaşdığınız, qeydə aldığınız və ya yayımladığınız zaman <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tətbiqi ekranınızda görünən və ya cihazınızda oxudulan hər şeyə giriş edə bilir. Odur ki, parollar, ödəniş detalları, mesajlar və ya digər həssas məlumatlarla bağlı diqqətli olun."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Paylaşdığınız, qeydə aldığınız və ya yayımladığınız zaman <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tətbiqi həmin tətbiqdə göstərilən və ya oxudulan hər şeyə giriş edə bilir. Odur ki, parollar, ödəniş detalları, mesajlar və ya digər həssas məlumatlarla bağlı diqqətli olun."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Davam edin"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Tətbiqi paylaşın və ya qeydə alın"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hamısını silin"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"İdarə edin"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarixçə"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 41633f7..5be177f 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Obaveštenje o sesiji snimanja ekrana je aktivno"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Želite da započnete snimanje?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Tokom snimanja Android sistem može da snimi osetljive informacije koje su vidljive na ekranu ili koje se puštaju na uređaju. To obuhvata lozinke, informacije o plaćanju, slike, poruke i zvuk."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Snimaj ceo ekran"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Snimaj jednu aplikaciju"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Android ima pristup kompletnom sadržaju koji je vidljiv na ekranu ili se pušta na uređaju dok snimate. Budite pažljivi sa lozinkama, informacijama o plaćanju, porukama ili drugim osetljivim informacijama."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Kada snimate aplikaciju, Android ima pristup kompletnom sadržaju koji je vidljiv ili se pušta u toj aplikaciji. Budite pažljivi sa lozinkama, informacijama o plaćanju, porukama ili drugim osetljivim informacijama."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Započni snimanje"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimaj zvuk"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk uređaja"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk sa uređaja, na primer, muzika, pozivi i melodije zvona"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkciju će imati pristup svim informacijama koje se prikazuju na ekranu ili reprodukuju sa uređaja tokom snimanja ili prebacivanja. To obuhvata informacije poput lozinki, informacija o plaćanju, slika, poruka i zvuka koji puštate."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Želite da počnete snimanje ili prebacivanje?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Želite da počnete snimanje ili prebacivanje pomoću aplikacije <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Želite da dozvolite deljenje i snimanje za <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Ceo ekran"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Jedna aplikacija"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Kada delite, snimate ili prebacujete, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup kompletnom sadržaju koji je vidljiv na ekranu ili se pušta na uređaju. Budite pažljivi sa lozinkama, informacijama o plaćanju, porukama ili drugim osetljivim informacijama."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kada delite, snimate ili prebacujete aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup kompletnom sadržaju koji je vidljiv ili se pušta u toj aplikaciji. Budite pažljivi sa lozinkama, informacijama o plaćanju, porukama ili drugim osetljivim informacijama."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Delite ili snimite aplikaciju"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Obriši sve"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 5c61919..881b59f 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Бягучае апавяшчэнне для сеанса запісу экрана"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Пачаць запіс?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Падчас запісу сістэма Android можа збіраць канфідэнцыяльную інфармацыю, якая адлюстроўваецца на экране вашай прылады ці прайграецца на ёй. Гэта могуць быць паролі, плацежная інфармацыя, фота, паведамленні і аўдыяданыя."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Запісаць змесціва ўсяго экрана"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Запісаць змесціва праграмы"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Калі адбываецца запіс, Android мае доступ да ўсяго змесціва, якое паказваецца на экране ці прайграецца на прыладзе. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў і іншай канфідэнцыяльнай інфармацыі."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Калі адбываецца запіс змесціва праграмы, Android мае доступ да ўсяго змесціва, якое паказваецца ці прайграецца ў праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў і іншай канфідэнцыяльнай інфармацыі."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Пачаць запіс"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Запісаць аўдыя"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Аўдыя з прылады"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Гук на вашай прыладзе, напрыклад музыка, выклікі і рынгтоны"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Падчас запісу ці трансляцыі служба, якая забяспечвае работу гэтай функцыі, будзе мець доступ да ўсёй інфармацыі, адлюстраванай на экране вашай прылады, ці той, якая праз яе прайграецца. Гэта інфармацыя ўключае паролі, звесткі пра аплату, фота, паведамленні і аўдыя, якое вы прайграяце."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Пачаць запіс або трансляцыю?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Пачаць запіс або трансляцыю з дапамогай праграмы \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Дазволіць праграме \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" абагульваць ці запісваць змесціва?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Увесь экран"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Адна праграма"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Калі пачынаецца абагульванне, запіс ці трансляцыя, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымлівае доступ да ўсяго змесціва, якое паказваецца на экране ці прайграецца на прыладзе. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў і іншай канфідэнцыяльнай інфармацыі."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Калі пачынаецца абагульванне, запіс ці трансляцыя змесціва праграмы, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> атрымлівае доступ да ўсяго змесціва, якое паказваецца ці прайграецца ў праграме. Таму прадухіліце паказ пароляў, плацежных рэквізітаў, паведамленняў і іншай канфідэнцыяльнай інфармацыі."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Далей"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Абагульванне або запіс праграмы"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Ачысціць усё"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Кіраваць"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Гісторыя"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c95e86e..fa6da94 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущо известие за сесия за записване на екрана"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Да се стартира ли записът?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"По време на записване системата Android може да запише и поверителна информация, която е показана на екрана или възпроизвеждана на устройството ви. Това включва пароли, данни за плащане, снимки, съобщения и аудио."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Записване на звук"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Аудио от устройството"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук от устройството ви, като например музика, обаждания и мелодии"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата, предоставяща тази функция, ще има достъп до цялата информация, която е видима на екрана или възпроизвеждана от устройството ви по време на записване или предаване. Това включва различна информация, като например пароли, данни за плащане, снимки, съобщения и възпроизвеждано аудио."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Да се стартира ли записване или предаване?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Да се стартира ли записване или предаване чрез <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Изчистване на всички"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Управление"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 0f7ddfc..8dc5f33 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"স্ক্রিন রেকর্ডিং সেশন চলার বিজ্ঞপ্তি"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"রেকর্ডিং শুরু করবেন?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"রেকর্ড করার সময়, আপনার স্ক্রিনে দেখানো বা ডিভাইসে চালানো যেকোনও ধরনের সংবেদনশীল তথ্য Android সিস্টেম ক্যাপচার করতে পারে। এর মধ্যে পাসওয়ার্ড, পেমেন্টের তথ্য, ফটো, মেসেজ এবং অডিও সম্পর্কিত তথ্য থাকে।"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"অডিও রেকর্ড করুন"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ডিভাইস অডিও"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"মিউজিক, কল এবং রিংটোনগুলির মতো আপনার ডিভাইস থেকে সাউন্ড"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"রেকর্ড করা বা কাস্টিং করার সময় আপনার স্ক্রিনে দেখানো বা ডিভাইসে চালানো হয়েছে এমন সমস্ত তথ্যের অ্যাক্সেস এই ফাংশন প্রদানকারী পরিষেবার কাছে থাকবে। এর মধ্যে আপনার পাসওয়ার্ড, পেমেন্টের বিবরণ, ফটো, মেসেজ এবং যে অডিও আপনি চালান সেগুলি সম্পর্কিত তথ্য রয়েছে।"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"রেকর্ড অথবা কাস্টিং শুরু করতে চান?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> দিয়ে রেকর্ড করা বা কাস্টিং শুরু করবেন?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"সবকিছু সাফ করুন"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"পরিচালনা করুন"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 19bbca6..ca0ff52 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Započeti snimanje?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, Android sistem može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Snimaj cijeli ekran"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Snimaj jednu aplikaciju"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Dok snimate, Android ima pristup svemu što se vidi na ekranu ili reproducira na uređaju. Zato budite oprezni s lozinkama, detaljima o plaćanju, porukama i drugim osjetljivim informacijama."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Dok snimate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Zato budite oprezni s lozinkama, detaljima o plaćanju, porukama i drugim osjetljivim informacijama."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Započni snimanje"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimi zvučni zapis"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk na uređaju"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk s vašeg uređaja, naprimjer muzika, pozivi i melodije zvona"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkciju će imati pristup svim informacijama koje se prikazuju na ekranu ili koje se reproduciraju s vašeg uređaja za vrijeme snimanja ili emitiranja. To obuhvata informacije kao što su lozinke, detalji o plaćanju, fotografije, poruke i zvuk koji reproducirate."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Započeti snimanje ili emitiranje?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Započeti snimanje ili emitiranje s aplikacijom <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Dozvoliti aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> da dijeli ili snima?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Cijeli ekran"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Jedna aplikacija"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Kada dijelite, snimate ili emitirate, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se vidi na ekranu ili što se reproducira na uređaju. Zato budite oprezni s lozinkama, detaljima o plaćanju, porukama i drugim osjetljivim informacijama."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kada aplikaciju dijelite, snimate ili emitirate, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Zato budite oprezni s lozinkama, detaljima o plaćanju, porukama i drugim osjetljivim informacijama."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dijelite ili snimite aplikaciju"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Očisti sve"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historija"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 839fa89..5e3fb33 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificació en curs d\'una sessió de gravació de la pantalla"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Vols iniciar la gravació?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durant la gravació, el sistema Android pot capturar qualsevol informació sensible que es mostri a la pantalla o que es reprodueixi al dispositiu. Això inclou contrasenyes, informació de pagament, fotos, missatges i àudio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Grava l\'àudio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Àudio del dispositiu"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"So del dispositiu, com ara música, trucades i sons de trucada"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servei que ofereix aquesta funció tindrà accés a tota la informació visible a la teva pantalla o que es reprodueix al dispositiu mentre graves o emets contingut, com ara contrasenyes, detalls dels pagaments, fotos, missatges i àudio que reprodueixis."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vols començar a gravar o emetre contingut?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vols començar a gravar o emetre contingut amb <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Esborra-ho tot"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestiona"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index aa6d812..b22656c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Trvalé oznámení o relaci nahrávání"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Spustit nahrávání?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Při nahrávání může systém Android zaznamenávat citlivé údaje, které jsou viditelné na obrazovce nebo které jsou přehrávány na zařízení. Týká se to hesel, údajů o platbě, fotek, zpráv a zvuků."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Nahrávat zvuk"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk zařízení"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk ze zařízení, například hudba, hovory a vyzvánění"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Služba, která tuto funkci poskytuje, bude mít při nahrávání nebo odesílání přístup ke všem informacím, které jsou viditelné na obrazovce nebo které jsou přehrávány ze zařízení. Týká se to i hesel, údajů o platbě, fotek, zpráv a přehrávaných zvuků."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Začít nahrávat nebo odesílat?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Začít nahrávat nebo odesílat s aplikací <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Smazat vše"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index c4afde1..9edb3377 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Konstant notifikation om skærmoptagelse"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Vil du starte optagelse?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Når du optager, kan Android-systemet registrere følsomme oplysninger, der er synlige på din skærm, eller som afspilles på din enhed. Dette inkluderer adgangskoder, betalingsoplysninger, fotos, meddelelser og lyd."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Optag lyd"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Enhedslyd"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Lyd fra din enhed såsom musik, opkald og ringetoner"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Tjenesten, der tilbyder denne funktion, får adgang til alle de oplysninger, der er synlige på din skærm, eller som afspilles på din enhed, når du optager eller caster. Dette omfatter oplysninger som f.eks. adgangskoder, betalingsoplysninger, billeder, beskeder og afspillet lyd."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vil du begynde at optage eller caste?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vil du begynde at optage eller caste via <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Ryd alle"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index fe3582a..7698065 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Fortlaufende Benachrichtigung für eine Bildschirmaufzeichnung"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Aufzeichnung starten?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Beim Aufnehmen kann das Android-System vertrauliche Informationen erfassen, die auf deinem Bildschirm angezeigt oder von deinem Gerät wiedergegeben werden. Das können Passwörter, Zahlungsinformationen, Fotos, Nachrichten und Audioinhalte sein."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Audio aufnehmen"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio des Geräts"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Audioinhalte auf deinem Gerät, wie Musik, Anrufe und Klingeltöne"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Der Anbieter dieser App erhält Zugriff auf alle Informationen, die auf deinem Bildschirm sichtbar sind oder von deinem Gerät wiedergegeben werden, während du aufnimmst oder streamst. Dazu gehören beispielsweise angezeigte Passwörter, Zahlungsdetails, Fotos, Nachrichten und Audioinhalte."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Aufnahme oder Stream starten?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Aufnehmen oder Streamen mit der App \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" starten?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Alle löschen"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Verwalten"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Verlauf"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 028f681..acaeddc 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ειδοποίηση σε εξέλιξη για μια περίοδο λειτουργίας εγγραφής οθόνης"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Έναρξη εγγραφής;"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Κατά την εγγραφή, το σύστημα Android μπορεί να καταγράψει τυχόν ευαίσθητες πληροφορίες που είναι ορατές στην οθόνη ή αναπαράγονται στη συσκευή σας. Σε αυτές περιλαμβάνονται οι κωδικοί πρόσβασης, οι πληροφορίες πληρωμής, οι φωτογραφίες, τα μηνύματα και ο ήχος."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Εγγραφή ολόκληρης οθόνης"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Εγγραφή μίας εφαρμογής"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Όταν κάνετε εγγραφή, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα ή άλλες ευαίσθητες πληροφορίες."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Όταν κάνετε εγγραφή μιας εφαρμογής, το Android έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα ή άλλες ευαίσθητες πληροφορίες."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Έναρξη εγγραφής"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Ηχογράφηση"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Ήχος συσκευής"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Ήχος από τη συσκευή σας, όπως μουσική, κλήσεις και ήχοι κλήσης"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Η υπηρεσία που παρέχει αυτήν τη λειτουργία θα έχει πρόσβαση σε όλες τις πληροφορίες που εμφανίζονται στην οθόνη σας ή που αναπαράγονται από τη συσκευή σας κατά την εγγραφή ή τη μετάδοση. Αυτό περιλαμβάνει πληροφορίες όπως κωδικούς πρόσβασης, στοιχεία πληρωμής, φωτογραφίες, μηνύματα και ήχο που αναπαράγετε."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Έναρξη εγγραφής ή μετάδοσης;"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Έναρξη εγγραφής ή μετάδοσης με <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>;"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Να επιτρέπεται στην εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> η κοινοποίηση ή η εγγραφή;"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Ολόκληρη την οθόνη"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Μία εφαρμογή"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Όταν κάνετε κοινοποίηση, εγγραφή ή μετάδοση, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό στην οθόνη σας ή αναπαράγεται στη συσκευή σας. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα ή άλλες ευαίσθητες πληροφορίες."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Όταν κάνετε κοινοποίηση, εγγραφή ή μετάδοση μιας εφαρμογής, η εφαρμογή <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> έχει πρόσβαση σε οτιδήποτε είναι ορατό ή αναπαράγεται στη συγκεκριμένη εφαρμογή. Επομένως, να είστε προσεκτικοί με τους κωδικούς πρόσβασης, τα στοιχεία πληρωμής, τα μηνύματα ή άλλες ευαίσθητες πληροφορίες."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Συνέχεια"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Κοινοποίηση ή εγγραφή εφαρμογής"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Διαγραφή όλων"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Διαχείριση"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Ιστορικό"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index a067d96..7c58eab 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Record entire screen"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Record a single app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"While you\'re recording an app, Android has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Start recording"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Allow <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> to share or record?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Entire screen"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"A single app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"When you\'re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 30183eb..c05b90e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Record entire screen"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Record a single app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"While you\'re recording an app, Android has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Start recording"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Allow <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> to share or record?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Entire screen"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"A single app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"When you\'re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index a067d96..7c58eab 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Record entire screen"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Record a single app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"While you\'re recording an app, Android has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Start recording"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Allow <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> to share or record?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Entire screen"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"A single app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"When you\'re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index a067d96..7c58eab 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ongoing notification for a screen record session"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Start recording?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"While recording, the Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages and audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Record entire screen"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Record a single app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"While you\'re recording an app, Android has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Start recording"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Record audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Device audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sound from your device, like music, calls and ringtones"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages and audio that you play."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Start recording or casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Start recording or casting with <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Allow <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> to share or record?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Entire screen"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"A single app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"When you\'re sharing, recording or casting, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"When you\'re sharing, recording or casting an app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> has access to anything shown or played on that app. So, be careful with passwords, payment details, messages or other sensitive information."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continue"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Share or record an app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Clear all"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index c09d197..9fc2374 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‏‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎Ongoing notification for a screen record session‎‏‎‎‏‎"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎Start Recording?‎‏‎‎‏‎"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎While recording, Android System can capture any sensitive information that’s visible on your screen or played on your device. This includes passwords, payment info, photos, messages, and audio.‎‏‎‎‏‎"</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‎Record entire screen‎‏‎‎‏‎"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‎Record a single app‎‏‎‎‏‎"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‏‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.‎‏‎‎‏‎"</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‎While you\'re recording an app, Android has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.‎‏‎‎‏‎"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎Start recording‎‏‎‎‏‎"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‏‎Record audio‎‏‎‎‏‎"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎Device audio‎‏‎‎‏‎"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‎‏‎Sound from your device, like music, calls, and ringtones‎‏‎‎‏‎"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‎The service providing this function will have access to all of the information that is visible on your screen or played from your device while recording or casting. This includes information such as passwords, payment details, photos, messages, and audio that you play.‎‏‎‎‏‎"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‎‎Start recording or casting?‎‏‎‎‏‎"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎Start recording or casting with ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎Allow ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎ to share or record?‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎Entire screen‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‎A single app‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎When you\'re sharing, recording, or casting, ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎ has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎When you\'re sharing, recording, or casting an app, ‎‏‎‎‏‏‎<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‎‏‎‎‏‏‏‎ has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‎Continue‎‏‎‎‏‎"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‎‎‎‏‎‏‎‎‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎Share or record an app‎‏‎‎‏‎"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎Clear all‎‏‎‎‏‎"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎Manage‎‏‎‎‏‎"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎History‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index f4f4999..2455ed4 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación constante para una sesión de grabación de pantalla"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"¿Comenzar a grabar?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durante la grabación, el sistema Android puede capturar cualquier información sensible que aparezca en la pantalla o que se reproduzca en el dispositivo. Se incluyen contraseñas, información de pago, fotos, mensajes y audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Grabar toda la pantalla"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Grabar una sola app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Mientras grabes, Android podrá acceder a todo el contenido visible en la pantalla o que reproduzcas en el dispositivo. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Mientras grabes una app, Android podrá acceder a todo el contenido que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Iniciar grabación"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabar audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio del dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sonidos del dispositivo, como música, llamadas y tonos"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que brinda esta función tendrá acceso a toda la información que sea visible en la pantalla o que reproduzcas en tu dispositivo durante una grabación o transmisión. Se incluyen las contraseñas, los detalles del pago, las fotos, los mensajes y el audio que reproduzcas."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Deseas comenzar a grabar o transmitir contenido?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Deseas iniciar una grabación o transmisión con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"¿Quieres permitir que <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> comparta o grabe contenido?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Pantalla completa"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Una sola app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Cuando compartas, grabes o transmitas contenido, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo aquel que sea visible en la pantalla o que reproduzcas en el dispositivo. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Cuando compartas, grabes o transmitas una app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> podrá acceder a todo el contenido que se muestre o reproduzca en ella. Por lo tanto, debes tener cuidado con contraseñas, detalles de pagos, mensajes y otra información sensible."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartir o grabar una app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index d6db89d..e9d1534 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación continua de una sesión de grabación de la pantalla"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"¿Empezar a grabar?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Mientras grabas, el sistema Android puede capturar información sensible que se muestre o se reproduzca en tu dispositivo, como contraseñas, datos de pago, fotos, mensajes y audio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabar audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio del dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sonido de tu dispositivo, como música, llamadas y tonos de llamada"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"El servicio que ofrece esta función tendrá acceso a toda la información que se muestre en la pantalla o se reproduzca en el dispositivo mientras grabas o envías contenido, incluyendo contraseñas, detalles de pagos, fotos, mensajes y audios que reproduzcas."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"¿Empezar a grabar o enviar contenido?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"¿Iniciar grabación o el envío de contenido en <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Borrar todo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 8d5c3c6..d7a8133 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -58,12 +58,12 @@
   </string-array>
   <string-array name="tile_states_flashlight">
     <item msgid="3465257127433353857">"No disponible"</item>
-    <item msgid="5044688398303285224">"Desactivada"</item>
+    <item msgid="5044688398303285224">"Desactivado"</item>
     <item msgid="8527389108867454098">"Activado"</item>
   </string-array>
   <string-array name="tile_states_rotation">
     <item msgid="4578491772376121579">"No disponible"</item>
-    <item msgid="5776427577477729185">"Desactivada"</item>
+    <item msgid="5776427577477729185">"Desactivado"</item>
     <item msgid="7105052717007227415">"Activado"</item>
   </string-array>
   <string-array name="tile_states_bt">
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 3edd02d..fae8364 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Kas alustada salvestamist?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Heli salvestamine"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Seadme heli"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Seadmest pärinev heli, nt muusika, kõned ja helinad"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Seda funktsiooni pakkuv teenus saab juurdepääsu kogu teabele, mis on teie ekraanikuval nähtav või mida seadmes salvestamise või ülekande ajal esitatakse. See hõlmab teavet, nagu paroolid, maksete üksikasjad, fotod, sõnumid ja esitatav heli."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Kas alustada salvestamist või ülekannet?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Kas alustada rakendusega <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> salvestamist või ülekannet?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tühjenda kõik"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Haldamine"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Ajalugu"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 9bc0051..cf53e32 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pantailaren grabaketa-saioaren jakinarazpen jarraitua"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Grabatzen hasi nahi duzu?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Pantaila grabatzen duzun bitartean, baliteke Android sistemak pantailan agertzen den edo gailuak erreproduzitzen duen kontuzko informazioa grabatzea; besteak beste, pasahitzak, ordainketa-informazioa, argazkiak, mezuak eta audioa."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Grabatu audioa"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Gailuaren audioa"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Gailuko soinuak; adibidez, musika, deiak eta tonuak"</string>
@@ -163,7 +173,7 @@
     <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_bluetooth_connected" msgid="4745196874551115205">"Bluetootha 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>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Hona konektatuta: <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -189,7 +199,7 @@
     <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"isiltasun osoa"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"alarmak soilik"</string>
     <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Ez molestatzeko modua."</string>
-    <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetooth-a."</string>
+    <string name="accessibility_quick_settings_bluetooth" msgid="8250942386687551283">"Bluetootha."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth bidezko konexioa aktibatuta dago."</string>
     <string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"Alarma ordu honetarako ezarri da: <xliff:g id="TIME">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_more_time" msgid="7646479831704665284">"Denbora gehiago."</string>
@@ -211,7 +221,7 @@
     <string name="start_dreams" msgid="9131802557946276718">"Pantaila-babeslea"</string>
     <string name="ethernet_label" msgid="2203544727007463351">"Ethernet"</string>
     <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Ez molestatzeko modua"</string>
-    <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth-a"</string>
+    <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetootha"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Ez dago parekatutako gailurik erabilgarri"</string>
     <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Bateria: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string>
     <string name="quick_settings_bluetooth_secondary_label_audio" msgid="780333390310051161">"Audioa"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Zerbait grabatzen edo igortzen duzunean, pantailan ikus daitekeen edo gailuak erreproduzitzen duen informazio guztia atzitu ahalko du funtzio hori eskaintzen duen zerbitzuak; besteak beste, pasahitzak, ordainketen xehetasunak, argazkiak, mezuak eta erreproduzitzen dituzun audioak."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Grabatzen edo igortzen hasi nahi duzu?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aplikazioarekin grabatzen edo igortzen hasi nahi duzu?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Garbitu guztiak"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Kudeatu"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
@@ -444,7 +468,7 @@
     <string name="stream_music" msgid="2188224742361847580">"Multimedia-edukia"</string>
     <string name="stream_alarm" msgid="16058075093011694">"Alarma"</string>
     <string name="stream_notification" msgid="7930294049046243939">"Jakinarazpena"</string>
-    <string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth-a"</string>
+    <string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetootha"</string>
     <string name="stream_dtmf" msgid="7322536356554673067">"Tonu anitzeko maiztasun duala"</string>
     <string name="stream_accessibility" msgid="3873610336741987152">"Erabilerraztasuna"</string>
     <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Jo tonua"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ce8f0ef..0a1007e 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"اعلان درحال انجام برای جلسه ضبط صفحه‌نمایش"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ضبط شروع شود؟"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"‏هنگام ضبط، «سیستم Android» می‌تواند هر اطلاعات حساسی را که روی صفحه‌نمایش شما نشان داده می‌شود یا روی دستگاه شما پخش می‌شود ضبط کند. این شامل گذرواژه‌ها، اطلاعات پرداخت، عکس‌ها، پیام‌ها، و صدا می‌شود."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"ضبط کل صفحه"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"ضبط یک برنامه"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"‏درحین ضبط کردن، Android به همه محتوایی که در صفحه‌تان نمایان است یا در دستگاهتان پخش می‌شود دسترسی دارد. بنابراین مراقب گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، یا دیگر اطلاعات حساس باشید."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"‏درحین ضبط برنامه، Android به همه محتوایی که در آن برنامه نمایان است یا پخش می‌شود دسترسی دارد. بنابراین مراقب گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، یا دیگر اطلاعات حساس باشید."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"شروع ضبط"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ضبط صدا"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"صدای دریافتی از دستگاه"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"صدای دریافتی از دستگاه، مثل موسیقی، تماس، و آهنگ زنگ"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"سرویس ارائه‌دهنده این عملکرد به همه اطلاعاتی که روی صفحه‌نمایش قابل‌مشاهد است و هنگام ضبط کردن یا پخش محتوا از دستگاهتان پخش می‌شود دسترسی خواهد داشت. این شامل اطلاعاتی مانند گذرواژه‌ها، جزئیات پرداخت، عکس‌ها، پیام‌ها، و صداهایی که پخش می‌کنید می‌شود."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ضبط یا پخش محتوا شروع شود؟"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"ضبط یا پخش محتوا با <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع شود؟"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"به <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> اجازه هم‌رسانی یا ضبط داده شود؟"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"کل صفحه"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"یک برنامه"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"وقتی درحال هم‌رسانی، ضبط، یا پخش محتوا هستید، <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> به همه محتوایی که در صفحه‌تان نمایان است یا در دستگاهتان پخش می‌شود دسترسی دارد. بنابراین مراقب گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، یا دیگر اطلاعات حساس باشید."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"وقتی درحال هم‌رسانی، ضبط، یا پخش محتوای برنامه‌ای هستید، <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> به همه محتوایی که در آن برنامه نمایان است یا پخش می‌شود دسترسی دارد. بنابراین مراقب گذرواژه‌ها، جزئیات پرداخت، پیام‌ها، یا دیگر اطلاعات حساس باشید."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ادامه"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"هم‌رسانی یا ضبط برنامه"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"پاک کردن همه موارد"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"مدیریت"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"سابقه"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 9738b05..14a65dc 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pysyvä ilmoitus näytön tallentamisesta"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Aloitetaanko tallennus?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Tallennuksen aikana Android-järjestelmä voi tallentaa mitä tahansa näytöllä näkyvää tai laitteen toistamaa arkaluontoista tietoa. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja audio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Tallenna audiota"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Laitteen audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Musiikki, puhelut, soittoäänet ja muut äänet laitteesta"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ominaisuuden tarjoavalla palvelulla on pääsy kaikkiin näytölläsi näkyviin tietoihin ja tietoihin laitteesi toistamasta sisällöstä tallennuksen tai striimauksen aikana. Näitä tietoja ovat esimerkiksi salasanat, maksutiedot, kuvat, viestit ja toistettava audiosisältö."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Aloitetaanko tallentaminen tai striimaus?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Haluatko, että <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> aloittaa tallennuksen tai striimauksen?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tyhjennä kaikki"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Muuta asetuksia"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index bbeb055..509cbc9 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement d\'écran"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Commencer l\'enregistrement?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durant l\'enregistrement, le système Android peut capturer de l\'information confidentielle qui s\'affiche sur votre écran ou qui joue sur votre appareil. Cela comprend les mots de passe, les renseignements sur le paiement, les photos, les messages et l\'audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Enregistrer l\'écran entier"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Enregistrer une seule appli"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Pendant l\'enregistrement, Android a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages ou toute autre information confidentielle."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Pendant l\'enregistrement, Android a accès à tout ce qui est affiché ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages ou toute autre information confidentielle."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Commencer l\'enregistrement"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Enregistrer des fichiers audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio de l\'appareil"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sons de l\'appareil comme la musique, les appels et les sonneries"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service offrant cette fonction aura accès à toute l\'information qui est visible sur votre écran ou sur ce qui joue sur votre appareil durant l\'enregistrement ou la diffusion. Cela comprend des renseignements comme les mots de passe, les détails du paiement, les photos, les messages et le contenu audio que vous faites jouer."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Commencer à enregistrer ou à diffuser?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Commencer à enregistrer ou à diffuser avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Autoriser <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> à partager ou à enregistrer?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Écran entier"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Une seule application"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Lorsque vous partagez, enregistrez ou diffusez, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est visible sur votre écran ou lu sur votre appareil. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages ou toute autre information confidentielle."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Lorsque vous partagez, enregistrez ou diffusez une application, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a accès à tout ce qui est affiché ou lu sur cette application. Par conséquent, soyez prudent avec les mots de passe, les détails du paiement, les messages ou toute autre information confidentielle."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuer"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Partager ou enregistrer une application"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 876bf18..9fdae3e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notification en cours pour une session d\'enregistrement de l\'écran"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Démarrer l\'enregistrement ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durant l\'enregistrement, le système Android peut capturer les infos sensibles affichées à l\'écran ou lues sur votre appareil. Cela inclut les mots de passe, les infos de paiement, les photos, les messages et l\'audio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Enregistrer l\'audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio de l\'appareil"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Son provenant de l\'appareil (musique, appels et sonneries, etc.)"</string>
@@ -323,7 +333,7 @@
     <item msgid="5640521437931460125">"Déplacer vers le haut"</item>
   </string-array>
     <string name="keyguard_retry" msgid="886802522584053523">"Balayez l\'écran vers le haut pour réessayer"</string>
-    <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser la NFC"</string>
+    <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Déverrouillez l\'écran pour pouvoir utiliser le NFC"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Cet appareil appartient à votre organisation"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Cet appareil appartient à <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Cet appareil est fourni par <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
@@ -337,11 +347,11 @@
     <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Aucune\ninterruption"</string>
     <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Priorité\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Alarmes\nuniquement"</string>
-    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge sans fil • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • En charge • Chargé dans <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> • Recharge rapide • Chargé dans <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> • Recharge lente • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
-    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge • Chargé dans <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_wireless" msgid="577856646141738675">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge sans fil • Temps restant : <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time" msgid="6492711711891071502">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • En charge • Temps restant : <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> • Recharge rapide • Temps restant : <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> • Recharge lente • Temps restant : <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
+    <string name="keyguard_indication_charging_time_dock" msgid="3149328898931741271">"<xliff:g id="PERCENTAGE">%2$s</xliff:g> • Recharge • Temps restant : <xliff:g id="CHARGING_TIME_LEFT">%1$s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string>
     <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Le service qui fournit cette fonction aura accès à toutes les infos visibles sur votre écran ou lues depuis votre appareil lors d\'un enregistrement ou de la diffusion d\'un contenu. Cela comprend, entre autres, vos mots de passe, les détails de vos paiements, vos photos, vos messages ou les contenus audio que vous écoutez."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Démarrer l\'enregistrement ou la diffusion ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Démarrer l\'enregistrement ou la diffusion avec <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tout effacer"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 7fd464e..36036aa 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificación en curso sobre unha sesión de gravación de pantalla"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Queres iniciar a gravación?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durante a gravación, o sistema Android pode captar información confidencial que apareza na pantalla ou se reproduza no dispositivo, como contrasinais, información de pago, fotos, mensaxes e audio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Gravar audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio do dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Son do dispositivo (por exemplo, música, chamadas e tons de chamada)"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O servizo que proporciona esta función terá acceso a toda a información visible na pantalla ou reproducida desde o teu dispositivo mentres graves ou emitas contido. Isto inclúe información como contrasinais, detalles de pago, fotos, mensaxes e o audio que reproduzas."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Queres iniciar a gravación ou a emisión?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Queres comezar a gravar ou emitir contido con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Eliminar todas"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 1562101..fd14277 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"સ્ક્રીન રેકોર્ડિંગ સત્ર માટે ચાલુ નોટિફિકેશન"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"રેકોર્ડિંગ શરૂ કરીએ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"રેકોર્ડ કરતી વખતે, Android System તમારી સ્ક્રીન પર દેખાતી હોય અથવા તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી કોઈપણ સંવેદનશીલ માહિતીને કૅપ્ચર કરી શકે છે. આમાં પાસવર્ડ, ચુકવણીની માહિતી, ફોટા, મેસેજ અને ઑડિયોનો સમાવેશ થાય છે."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"પૂર્ણ સ્ક્રીન રેકોર્ડ કરો"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"કોઈ એક ઍપ રેકોર્ડ કરો"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"જ્યારે તમે રેકોર્ડ કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પર દેખાતી હોય કે તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી કોઈપણ વસ્તુનો ઍક્સેસ Android ધરાવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ અથવા અન્ય સંવેદનશીલ માહિતીની બાબતે સાવચેત રહેશો."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"જ્યારે તમે કોઈ ઍપ રેકોર્ડ કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી કોઈપણ વસ્તુનો ઍક્સેસ Android ધરાવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ અથવા અન્ય સંવેદનશીલ માહિતીની બાબતે સાવચેત રહેશો."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"રેકોર્ડિંગ શરૂ કરો"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ઑડિયો રેકોર્ડ કરો"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ડિવાઇસનો ઑડિયો"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"મ્યુઝિક, કૉલ અને રિંગટોન જેવા તમારા ડિવાઇસના સાઉન્ડ"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"રેકોર્ડ અથવા કાસ્ટ કરતી વખતે, આ સુવિધા આપતી સેવાને તમારી સ્ક્રીન પર દેખાતી હોય અથવા તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી બધી માહિતીનો ઍક્સેસ હશે. આમાં પાસવર્ડ, ચુકવણીની વિગતો, ફોટા, મેસેજ અને તમે ચલાવો છો તે ઑડિયો જેવી માહિતીનો સમાવેશ થાય છે."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"શું રેકોર્ડ અથવા કાસ્ટ કરવાનું શરૂ કરીએ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> વડે રેકોર્ડ અથવા કાસ્ટ કરવાનું શરૂ કરીએ?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"શુ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>ને શેર અથવા રેકોર્ડ કરવાની મંજૂરી આપીએ?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"પૂર્ણ સ્ક્રીન"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"કોઈ એક ઍપ"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"જ્યારે તમે શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તમારી સ્ક્રીન પર દેખાતી હોય કે તમારા ડિવાઇસ પર ચલાવવામાં આવતી હોય તેવી કોઈપણ વસ્તુનો ઍક્સેસ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ધરાવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ અથવા અન્ય સંવેદનશીલ માહિતીની બાબતે સાવચેત રહેશો."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"જ્યારે તમે કોઈ ઍપ શેર, રેકોર્ડ અથવા કાસ્ટ કરી રહ્યાં હો, ત્યારે તે ઍપ પર બતાવવામાં કે ચલાવવામાં આવતી હોય તેવી કોઈપણ વસ્તુનો ઍક્સેસ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ધરાવે છે. તેથી પાસવર્ડ, ચુકવણીની વિગતો, મેસેજ અથવા અન્ય સંવેદનશીલ માહિતીની બાબતે સાવચેત રહેશો."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ચાલુ રાખો"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"કોઈ ઍપ શેર કરો અથવા રેકોર્ડ કરો"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"બધુ સાફ કરો"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"મેનેજ કરો"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ઇતિહાસ"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 5664c6a..3d1b1ea 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रिकॉर्ड सेशन के लिए जारी सूचना"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"क्या आपको रिकॉर्डिंग शुरू करनी है?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"रिकॉर्ड करते समय, Android सिस्टम आपकी स्क्रीन पर दिखने वाली या चलाई जाने वाली संवेदनशील जानकारी को कैप्चर कर सकता है. इसमें पासवर्ड, पैसे चुकाने से जुड़ी जानकारी, फ़ोटो, मैसेज, और ऑडियो शामिल हैं."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ऑडियो रिकॉर्ड करें"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिवाइस ऑडियो"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"आपके डिवाइस से आने वाली आवाज़ जैसे कि संगीत, कॉल, और रिंगटोन"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"इस फ़ंक्शन को उपलब्ध कराने वाली सेवा, रिकॉर्ड या कास्ट करते समय, आपकी स्क्रीन पर दिखने वाली या चलाई जाने वाली जानकारी को ऐक्सेस कर सकती है. इसमें पासवर्ड, पैसे चुकाने से जुड़ी जानकारी, फ़ोटो, मैसेज, और चलाए जाने वाले ऑडियो शामिल हैं."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रिकॉर्डिंग या कास्ट करना शुरू करें?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> का इस्तेमाल करके रिकॉर्ड और कास्ट करना शुरू करें?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सभी को हटाएं"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"मैनेज करें"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 1a9768c..8305da8 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Tekuća obavijest za sesiju snimanja zaslona"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Želite li započeti snimanje?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Za vrijeme snimanja sustav Android može snimiti osjetljive podatke koji su vidljivi na vašem zaslonu ili se reproduciraju na vašem uređaju. To uključuje zaporke, podatke o plaćanju, fotografije, poruke i zvuk."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Snimi cijeli zaslon"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Snimi jednu aplikaciju"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Dok snimate, Android ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Dok snimate aplikaciju, Android ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Započni snimanje"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimanje zvuka"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk na uređaju"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk s vašeg uređaja, poput glazbe, poziva i melodija zvona"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Usluga koja pruža ovu funkcionalnost imat će pristup svim podacima koji su vidljivi na vašem zaslonu ili koji se reproduciraju s vašeg uređaja tijekom snimanja ili emitiranja. To uključuje podatke kao što su zaporke, podaci o plaćanju, fotografije, poruke i audiozapisi koje reproducirate."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Želite li započeti snimanje ili emitiranje?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Želite li započeti snimanje ili emitiranje pomoću aplikacije <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Želite li dopustiti aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> da dijeli ili snima?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Cijeli zaslon"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Jedna aplikacija"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Kad dijelite, snimate ili emitirate, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što je vidljivo na vašem zaslonu ili se reproducira na vašem uređaju. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kad dijelite, snimate ili emitirate aplikaciju, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ima pristup svemu što se prikazuje ili reproducira u toj aplikaciji. Stoga pazite na zaporke, podatke o plaćanju, poruke i druge osjetljive podatke."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Nastavi"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Dijeljenje ili snimanje pomoću aplikacije"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši sve"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Povijest"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 3fc12ff..746e3c0 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Folyamatban lévő értesítés képernyőrögzítési munkamenethez"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Elindítja a felvételt?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"A felvétel készítése során az Android rendszer rögzítheti az eszközön lejátszott, illetve a képernyőjén megjelenő bizalmas információkat. Ide tartoznak például a jelszavak, a fizetési információk, a fotók, az üzenetek és az audiotartalmak is."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Teljes képernyő rögzítése"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Egyetlen alkalmazás rögzítése"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Rögzítés közben az Android a képernyőn látható vagy az eszközön lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel és más bizalmas információkkal."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Alkalmazás rögzítése közben az Android az adott appban látható vagy lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel és más bizalmas információkkal."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Rögzítés indítása"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Hang rögzítése"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Eszköz hangja"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Az eszköz által lejátszott hangok, például zeneszámok, hívások és csengőhangok"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"A funkciót biztosító szolgáltatás hozzáfér majd minden olyan információhoz, amely látható az Ön képernyőjén, illetve amelyet az Ön eszközéről játszanak le rögzítés vagy átküldés közben. Ez olyan információkat is tartalmaz, mint a jelszavak, a fizetési részletek, fotók, üzenetek és lejátszott audiotartalmak."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Biztosan elkezdi a rögzítést vagy az átküldést?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Elkezdi a rögzítést vagy átküldést a következővel: <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Engedélyezi a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> számára a megosztást és rögzítést?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Teljes képernyő"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Egyetlen alkalmazás"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Amikor Ön megosztást, rögzítést vagy átküldést végez, a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> a képernyőn látható vagy az eszközön lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel és más bizalmas információkkal."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Amikor Ön megoszt, rögzít vagy átküld egy alkalmazást, a(z) <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> az adott appban látható vagy lejátszott minden tartalomhoz hozzáfér. Ezért legyen elővigyázatos a jelszavakkal, a fizetési adatokkal, az üzenetekkel és más bizalmas információkkal."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Folytatás"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Alkalmazás megosztása és rögzítése"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Az összes törlése"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Kezelés"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Előzmények"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index b423a26..fed009f 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Էկրանի տեսագրման աշխատաշրջանի ընթացիկ ծանուցում"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Սկսե՞լ տեսագրումը"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Տեսագրման ընթացքում Android համակարգը կարող է գրանցել անձնական տեղեկություններ, որոնք տեսանելի են էկրանին կամ նվագարկվում են ձեր սարքում։ Սա ներառում է այնպիսի տեղեկություններ, ինչպիսիք են, օրինակ, գաղտնաբառերը, վճարային տվյալները, լուսանկարները, հաղորդագրությունները և նվագարկվող աուդիո ֆայլերը։"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Ձայնագրել"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Սարքի ձայները"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Ձեր սարքի ձայները, օրինակ՝ երաժշտությունը, զանգերն ու զանգերանգները"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ձայնագրման և հեռարձակման ընթացքում ծառայությունների մատակարարին հասանելի կլինեն ձեր սարքի էկրանին ցուցադրվող տեղեկությունները և ձեր սարքով նվագարկվող նյութերը։ Սա ներառում է այնպիսի տեղեկություններ, ինչպիսիք են, օրինակ, գաղտնաբառերը, վճարային տվյալները, լուսանկարները, հաղորդագրությունները և նվագարկվող աուդիո ֆայլերը։"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Սկսե՞լ ձայնագրումը կամ հեռարձակումը"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Սկսե՞լ ձայնագրումը կամ հեռարձակումը <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> հավելվածով"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Մաքրել բոլորը"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Կառավարել"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Պատմություն"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c52b81fa..0156900 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifikasi yang sedang berjalan untuk sesi rekaman layar"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Mulai merekam?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Saat merekam, Sistem Android dapat ikut merekam informasi sensitif yang terlihat di layar atau diputar di perangkat Anda. Informasi ini mencakup sandi, info pembayaran, foto, pesan, dan audio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Rekam audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio perangkat"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Suara dari perangkat Anda, seperti musik, panggilan, dan nada dering"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Layanan yang menyediakan fungsi ini akan memiliki akses ke semua informasi yang terlihat di layar atau diputar dari perangkat saat merekam atau melakukan transmisi. Ini mencakup informasi seperti sandi, detail pembayaran, foto, pesan, dan audio yang Anda putar."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Mulai merekam atau melakukan transmisi?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Mulai merekam atau melakukan transmisi dengan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hapus semua"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Kelola"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histori"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 25ca6ae..7622ad4 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Áframhaldandi tilkynning fyrir skjáupptökulotu"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Hefja upptöku?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Á meðan tekið er upp getur Android kerfið fangað viðkvæmar upplýsingar sem sjást á skjánum eða spilast í tækinu. Þar á meðal eru upplýsingar á borð við aðgangsorð, greiðsluupplýsingar, myndir, skilaboð og hljóð."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Taka upp hljóð"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Hljóð tækis"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Hljóð úr tækinu á borð við tónlist, símtöl og hringitóna"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Þjónustan sem býður upp á þennan eiginleika fær aðgang að öllum upplýsingum sem sjást á skjánum eða eru spilaðar í tækinu á meðan upptaka eða útsending er í gangi, þar á meðal aðgangsorði, greiðsluupplýsingum, myndum, skilaboðum og hljóðefni sem þú spilar."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Viltu hefja upptöku eða útsendingu?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Viltu hefja upptöku eða útsendingu með <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hreinsa allt"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Stjórna"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Ferill"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 41b1220..736c6b9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notifica costante per una sessione di registrazione dello schermo"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Avviare la registrazione?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durante la registrazione, il sistema Android può acquisire informazioni sensibili visibili sullo schermo o riprodotte sul tuo dispositivo, tra cui password, dati di pagamento, foto, messaggi e audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Registra l\'intero schermo"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Registra una singola pp"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Quando registri, Android ha accesso a qualsiasi elemento visibile sul tuo schermo o in riproduzione sul tuo dispositivo. Presta quindi attenzione a password, dati di pagamento, messaggi o altre informazioni sensibili."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Quando registri un\'app, Android ha accesso a qualsiasi elemento visualizzato o riprodotto sull\'app. Presta quindi attenzione a password, dati di pagamento, messaggi o altre informazioni sensibili."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Avvia registrazione"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Registra audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio del dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Suoni del dispositivo, come musica, chiamate e suonerie"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Il servizio che offre questa funzione avrà accesso a tutte le informazioni visibili sul tuo schermo o riprodotte dal tuo dispositivo durante la registrazione o la trasmissione. Sono incluse informazioni quali password, dettagli sui pagamenti, foto, messaggi e audio riprodotto."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vuoi avviare la registrazione o la trasmissione?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vuoi avviare la registrazione o la trasmissione con <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Consenti a <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> di condividere o registrare?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Schermo intero"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Una sola app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Quando condividi, registri o trasmetti, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ha accesso a qualsiasi elemento visibile sul tuo schermo o in riproduzione sul tuo dispositivo. Presta quindi attenzione a password, dati di pagamento, messaggi o altre informazioni sensibili."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando condividi, registri o trasmetti un\'app, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ha accesso a qualsiasi elemento visualizzato o riprodotto sull\'app. Presta quindi attenzione a password, dati di pagamento, messaggi o altre informazioni sensibili."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continua"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Condividi o registra un\'app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Cancella tutto"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestisci"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Cronologia"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e5e37f5..8a1ba7c 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"התראה מתמשכת לסשן הקלטת מסך"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"להתחיל את ההקלטה?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"‏בזמן ההקלטה, מערכת Android יכולה לתעד מידע רגיש שגלוי במסך או מופעל במכשיר שלך. מידע זה כולל סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"הקלטה של כל המסך"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"הקלטה של אפליקציה אחת"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"‏בזמן ההקלטה, תהיה ל-Android גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"‏בזמן הקלטה של אפליקציה, תהיה ל-Android גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"התחלת ההקלטה"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"הקלטת אודיו"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"אודיו מהמכשיר"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"צלילים מהמכשיר, כמו מוזיקה, שיחות ורינגטונים"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"‏לשירות שמספק את הפונקציה הזו תהיה גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך בזמן הקלטה או העברה (cast) – כולל פרטים כמו סיסמאות, פרטי תשלום, תמונות, הודעות ואודיו שמושמע מהמכשיר."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"‏להתחיל להקליט או להעביר (cast)?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"‏להתחיל להקליט או להעביר (cast) באמצעות <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"לאפשר לאפליקציה <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> לשתף או להקליט?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"כל המסך"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"אפליקציה אחת"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"‏בזמן שיתוף, הקלטה או העברה (cast) תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל הפרטים שגלויים במסך שלך או מופעלים מהמכשיר שלך. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"‏בזמן שיתוף, הקלטה או העברה (cast) של אפליקציה, תהיה ל-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> גישה לכל מה שגלוי באפליקציה או מופעל מהאפליקציה. כדאי להיזהר עם סיסמאות, פרטי תשלום, הודעות או מידע רגיש אחר."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"המשך"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"שיתוף או הקלטה של אפליקציה"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ניקוי הכול"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"היסטוריה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 15089a4..a2839e8 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"画面の録画セッション中の通知"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"録画を開始しますか?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"録画中に機密情報が画面に表示されたりデバイスで再生されたりした場合、Android システムでキャプチャされることがあります。これには、パスワード、お支払い情報、写真、メッセージ、音声などが含まれます。"</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"画面全体を録画する"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"1 つのアプリを録画する"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"録画中は、画面に表示されている内容やデバイスで再生されている内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージなどの機密情報にご注意ください。"</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"アプリの録画中は、そのアプリで表示されている内容や再生されている内容に Android がアクセスできるため、パスワード、お支払いの詳細、メッセージなどの機密情報にご注意ください。"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"録画を開始"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"録音"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"デバイスの音声"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"デバイスからの音(音楽、通話、着信音など)"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"この機能を提供するサービスは、録画中またはキャスト中に画面上に表示される情報、またはキャスト先に転送される情報すべてにアクセスできます。これには、パスワード、お支払いの詳細、写真、メッセージ、再生される音声などが含まれます。"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"録画やキャストを開始しますか?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> で録画やキャストを開始しますか?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> に共有や録画を許可しますか?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"画面全体"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"1 つのアプリ"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"共有、録画、キャスト中は、画面に表示されている内容やデバイスで再生している内容に <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> がアクセスできるため、パスワード、お支払いの詳細、メッセージなどの機密情報にご注意ください。"</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"アプリの共有、録画、キャスト中は、そのアプリで表示されている内容や再生している内容に <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> がアクセスできるため、パスワード、お支払いの詳細、メッセージなどの機密情報にご注意ください。"</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"続行"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"アプリの共有、録画"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"すべて消去"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"履歴"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 76033ca..6768773 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"უწყვეტი შეტყობინება ეკრანის ჩაწერის სესიისთვის"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"დაიწყოს ჩაწერა?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ჩაწერის განმავლობაში Android სისტემას შეუძლია აღბეჭდოს ნებისმიერი სენსიტიური ინფორმაცია, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება. აღნიშნული მოიცავს პაროლებს, გადახდის დეტალებს, ფოტოებს, შეტყობინებებსა და აუდიოს."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"მთელი ეკრანის ჩაწერა"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"ერთი აპის ჩაწერა"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"სანამ აპის ჩაწერას ახორციელებთ, Android-ს აქვს წვდომა ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენი მოწყობილობის მეშვეობით. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"სანამ აპის ჩაწერას ახორციელებთ, Android-ს აქვს წვდომა ყველაფერზე, რაც ჩანს აპში ან ითამაშეთ. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"ჩაწერის დაწყება"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"აუდიოს ჩაწერა"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"მოწყობილობის აუდიო"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"ხმა თქვენი მოწყობილობიდან, როგორიც არის მუსიკა, საუბარი და ზარები"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ამ ფუნქციის მომწოდებელ სერვისს ექნება წვდომა ყველა ინფორმაციაზე, რომელიც თქვენს ეკრანზე გამოჩნდება ან თქვენს მოწყობილობაზე დაიკვრება ჩაწერის ან ტრანსლირების განმავლობაში. აღნიშნული მოიცავს ისეთ ინფორმაციას, როგორიც არის პაროლები, გადახდის დეტალები, ფოტოები, შეტყობინებები და თქვენ მიერ დაკრული აუდიო."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"დაიწყოს ჩაწერა ან ტრანსლირება?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"დაიწყოს ჩაწერა ან ტრანსლირება <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-ით?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"გსურთ დართოთ ნება <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> გაზიარების ან ჩაწერისთვის?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"მთელი ეკრანი"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"ერთი აპი"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"როდესაც თქვენ აზიარებთ, ჩაწერთ ან ტრანსლირებთ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> აქვს წვდომა ყველაფერზე, რაც ჩანს თქვენს ეკრანზე ან უკრავს თქვენს მოწყობილობაზე. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"აპის გაზიარებისას, ჩაწერისას ან ტრანსლირებისას <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> აქვს წვდომა აქვს ყველაფერზე, რაც ჩანს აპში ან ითამაშეთ. ამიტომ იყავით ფრთხილად პაროლებთან, გადახდის დეტალებთან, შეტყობინებებთან ან სხვა მგრძნობიარე ინფორმაციასთან."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"გაგრძელება"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"გააზიარეთ ან ჩაწერეთ აპი"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ყველას გასუფთავება"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"მართვა"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ისტორია"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 4cebc9b..d6631e7 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды бейнеге жазудың ағымдағы хабарландыруы"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Жазу басталсын ба?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Android жүйесі экранда көрсетілетін немесе құрылғыда ойнатылатын құпия ақпаратты жазып алуы мүмкін. Ондай ақпаратқа құпия сөздер, төлем ақпараты, фотосуреттер, хабарлар және аудио жатады."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио жазу"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Құрылғыдан шығатын дыбыс"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Музыка, қоңыраулар және рингтондар сияқты құрылғыдан шығатын дыбыс"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Осы функцияны ұсынатын қызмет жазу не трансляциялау кезінде экранда көрсетілетін немесе құрылғыда дыбысталатын ақпаратты пайдалана алады. Бұған құпия сөздер, төлем туралы мәліметтер, суреттер, хабарлар және аудиоматериалдар кіреді."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жазу немесе трансляциялау басталсын ба?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> арқылы жазу немесе трансляциялау басталсын ба?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Барлығын тазалау"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Басқару"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Тарих"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index bb1768a..fb6ec60 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ការជូនដំណឹង​ដែល​កំពុង​ដំណើរការ​សម្រាប់​រយៈពេលប្រើ​ការថត​សកម្មភាព​អេក្រង់"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ចាប់ផ្តើម​ថត​ឬ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"នៅពេល​កំពុងថត ប្រព័ន្ធ Android អាច​ថត​ព័ត៌មាន​រសើប​ដែលអាច​មើលឃើញ​នៅលើ​អេក្រង់​របស់អ្នក ឬដែល​បានចាក់​នៅលើ​ឧបករណ៍​របស់អ្នក។ ព័ត៌មាននេះ​រួមមាន​ពាក្យសម្ងាត់ ព័ត៌មាន​អំពី​ការបង់ប្រាក់ រូបថត សារ និងសំឡេង។"</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"ថតអេក្រង់ទាំងមូល"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"ថតកម្មវិធីតែមួយ"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"នៅពេលអ្នកកំពុងថត Android មានសិទ្ធិចូលប្រើប្រាស់អ្វីៗដែលបង្ហាញឱ្យឃើញនៅលើអេក្រង់របស់អ្នក ឬលេងនៅលើឧបករណ៍របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិតអំពី​ការ​ទូទាត់ប្រាក់ សារ ឬព័ត៌មានរសើបផ្សេងទៀត។"</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"នៅពេលអ្នកកំពុងថតកម្មវិធី Android មានសិទ្ធិចូលប្រើប្រាស់អ្វីៗដែលបង្ហាញ ឬលេងនៅលើកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិតអំពី​ការ​ទូទាត់ប្រាក់ សារ ឬព័ត៌មានរសើបផ្សេងទៀត។"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"ចាប់ផ្តើមថត"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ថត​សំឡេង"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"សំឡេង​ឧបករណ៍"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"សំឡេង​ពី​ឧបករណ៍​របស់អ្នក​ដូចជា តន្ត្រី ការហៅទូរសព្ទ និងសំឡេងរោទ៍​ជាដើម"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"សេវាកម្មដែល​ផ្ដល់​មុខងារ​នេះ​នឹងមាន​សិទ្ធិ​ចូលប្រើ​ព័ត៌មាន​ទាំងអស់​ដែល​អាច​មើលឃើញ​នៅលើ​អេក្រង់​របស់អ្នក ឬ​ដែលចាក់​ពីឧបករណ៍​របស់អ្នក នៅពេល​កំពុង​ថត ឬភ្ជាប់។ ព័ត៌មាន​នេះមាន​ដូចជា ពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិត​អំពីការទូទាត់​ប្រាក់ រូបថត សារ និង​សំឡេង​ដែល​អ្នកចាក់​ជាដើម។"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ចាប់ផ្ដើម​ថត ឬភ្ជាប់​មែនទេ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"ចាប់ផ្ដើម​ថត ឬភ្ជាប់​ដោយប្រើ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ឬ?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"អនុញ្ញាតឱ្យ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ចែករំលែក ឬថតទេ?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"អេក្រង់ទាំងមូល"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"កម្មវិធីតែមួយ"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬបញ្ជូន <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មានសិទ្ធិចូលប្រើប្រាស់អ្វីៗដែលបង្ហាញឱ្យឃើញនៅលើអេក្រង់របស់អ្នក ឬលេងនៅលើឧបករណ៍របស់អ្នក។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិតអំពី​ការ​ទូទាត់ប្រាក់ សារ ឬព័ត៌មានរសើបផ្សេងទៀត។"</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"នៅពេលអ្នកកំពុងចែករំលែក ថត ឬបញ្ជូនកម្មវិធី <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> មានសិទ្ធិចូលប្រើប្រាស់អ្វីៗដែលបង្ហាញ ឬលេងនៅលើកម្មវិធីនោះ។ ដូច្នេះ សូមប្រុងប្រយ័ត្នចំពោះពាក្យសម្ងាត់ ព័ត៌មាន​លម្អិតអំពី​ការ​ទូទាត់ប្រាក់ សារ ឬព័ត៌មានរសើបផ្សេងទៀត។"</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"បន្ត"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ចែករំលែក ឬថតកម្មវិធី"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"សម្អាត​ទាំងអស់"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"គ្រប់គ្រង"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ប្រវត្តិ"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 8d270e3..713d20d 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ಸ್ಕ್ರೀನ್ ರೆಕಾರ್ಡಿಂಗ್ ಸೆಶನ್‌ಗಾಗಿ ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಅಧಿಸೂಚನೆ"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸಬೇಕೆ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ರೆಕಾರ್ಡಿಂಗ್ ಸಮಯದಲ್ಲಿ, ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಗೋಚರಿಸುವ ಅಥವಾ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲಾದ ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು Android ಸಿಸ್ಟಂ ಕ್ಯಾಪ್ಚರ್ ಮಾಡಬಹುದು. ಇದು ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ಮಾಹಿತಿ, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಆಡಿಯೋವನ್ನು ಒಳಗೊಂಡಿದೆ."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ಆಡಿಯೋ ರೆಕಾರ್ಡ್‌ ಮಾಡಿ"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ಸಾಧನದ ಆಡಿಯೋ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"ನಿಮ್ಮ ಸಾಧನದ ಧ್ವನಿ ಉದಾ: ಸಂಗೀತ, ಕರೆಗಳು ಮತ್ತು ರಿಂಗ್‌ಟೋನ್‌ಗಳು"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ಈ ವೈಶಿಷ್ಟ್ಯವು ಒದಗಿಸುವ ಸೇವೆಗಳು, ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುವ ಅಥವಾ ರೆಕಾರ್ಡಿಂಗ್ ಅಥವಾ ಬಿತ್ತರಿಸುವಾಗ ಸಾಧನದಲ್ಲಿ ಪ್ಲೇ ಆಗುವ ಎಲ್ಲಾ ಮಾಹಿತಿಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರುತ್ತವೆ. ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಪಾವತಿ ವಿವರಗಳು, ಫೋಟೋಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಆಡಿಯೋ ಪ್ಲೇಬ್ಯಾಕ್‌ನಂತಹ ಮಾಹಿತಿಯನ್ನು ಇದು ಒಳಗೊಂಡಿದೆ."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ರೆಕಾರ್ಡಿಂಗ್ ಅಥವಾ ಬಿತ್ತರಿಸುವಿಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಬೇಕೆ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ಮೂಲಕ ರೆಕಾರ್ಡಿಂಗ್, ಬಿತ್ತರಿಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸುವುದೇ?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index b5bf91f..290c517 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"화면 녹화 세션에 관한 지속적인 알림"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"녹화를 시작하시겠습니까?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Android 시스템이 녹화 중에 화면에 표시되거나 기기에서 재생되는 민감한 정보를 캡처할 수 있습니다. 여기에는 비밀번호, 결제 정보, 사진, 메시지 및 오디오가 포함됩니다."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"오디오 녹음"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"기기 오디오"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"음악, 통화, 벨소리와 같이 기기에서 나는 소리"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"이 기능을 제공하는 서비스는 녹화 또는 전송 중에 화면에 표시되거나 기기에서 재생되는 모든 정보에 액세스할 수 있습니다. 여기에는 비밀번호, 결제 세부정보, 사진, 메시지, 재생하는 오디오 같은 정보가 포함됩니다."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"녹화 또는 전송을 시작하시겠습니까?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>으로 녹화 또는 전송을 시작하시겠습니까?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"모두 지우기"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"관리"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"기록"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 2d8e4a6..004ec73 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Экранды жаздыруу сеансы боюнча учурдагы билдирме"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Жаздырып баштайсызбы?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Сырсөздөр, төлөм маалыматы, сүрөттөр, билдирүүлөр жана аудиофайлдар сыяктуу экраныңызда көрүнүп турган жана түзмөктө ойноп жаткан бардык купуя маалымат жазылып калат."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Бүтүндөй экранды жаздыруу"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Жалгыз колдонмону жаздыруу"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Жаздырып жатканыңызда Android экраныңызда көрүнүп жана түзмөктө ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Жаздырып жатканыңызда Android ал колдонмодо көрүнүп жана ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Жаздырып баштоо"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио жаздыруу"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Түзмөктөгү аудиолор"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Музыка, чалуулар жана шыңгырлар сыяктуу түзмөгүңүздөгү добуштар"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Жаздырып же тышкы экранга чыгарып жатканда, бул колдонмо экраныңыздагы бардык маалыматты же түзмөктө ойнолуп жаткан бардык нерселерди (сырсөздөрдү, төлөмдүн чоо-жайын, сүрөттөрдү, билдирүүлөрдү жана угуп жаткан аудиофайлдарды) көрө алат."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Жаздырып же тышкы экранга чыгарып баштайсызбы?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосу аркылуу жаздырып же тышкы экранга чыгарып баштайсызбы?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> колдонмосуна бөлүшүүгө же жаздырууга уруксат бересизби?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Бүтүндөй экран"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Жалгыз колдонмо"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Бөлүшүп, жаздырып же тышкы экранда бөлүшкөндө <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> экраныңызда көрүнүп жана түзмөктө ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Бөлүшүп, жаздырып же тышкы экранда бөлүшкөндө <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ал колдонмодо көрүнүп жана ойнотулуп жаткан нерселерге мүмкүнчүлүк алат. Андыктан сырсөздөрдү, төлөм маалыматын, билдирүүлөрдү жана башка купуя маалыматты көрсөтүп албаңыз."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Улантуу"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Колдонмону бөлүшүү же жаздыруу"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Баарын тазалап салуу"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Башкаруу"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Таржымал"</string>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 9d7b01c..49ef330 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -59,4 +59,5 @@
     <dimen name="large_dialog_width">348dp</dimen>
 
     <dimen name="qs_panel_padding_top">@dimen/qqs_layout_margin_top</dimen>
+    <dimen name="qs_panel_padding_top_combined_headers">@dimen/qs_panel_padding_top</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 69ff576..088ae17 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ການແຈ້ງເຕືອນສຳລັບເຊດຊັນການບັນທຶກໜ້າຈໍໃດໜຶ່ງ"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ເລີ່ມການບັນທຶກບໍ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ໃນລະຫວ່າງການບັນທຶກ, ລະບົບ Android ຈະສາມາດບັນທຶກຂໍ້ມູນທີ່ລະອຽດອ່ອນໃດກໍຕາມທີ່ສະແດງຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນທ່ານ. ນີ້ຮວມເຖິງລະຫັດຜ່ານ, ຂໍ້ມູນການຈ່າຍເງິນ, ຮູບ, ຂໍ້ຄວາມ ແລະ ສຽງນຳ."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"ບັນທຶກໝົດໜ້າຈໍ"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"ບັນທຶກແອັບດຽວ"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"ໃນຂະນະທີ່ທ່ານກຳລັງບັນທຶກ, Android ຈະມີສິດເຂົ້າເຖິງສິ່ງທີ່ເບິ່ງໃຫ້ຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ດັ່ງນັ້ນໃຫ້ລະມັດລະວັງເລື່ອງລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ ຫຼື ຂໍ້ມູນທີ່ລະອຽດອ່ອນອື່ນໆ."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"ໃນຂະນະທີ່ທ່ານກຳລັງບັນທຶກແອັບ, Android ຈະມີສິດເຂົ້າເຖິງສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ໃນແອັບນັ້ນ. ດັ່ງນັ້ນໃຫ້ລະມັດລະວັງກ່ຽວກັບລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ ຫຼື ຂໍ້ມູນທີ່ລະອຽດອ່ອນອື່ນໆ."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"ເລີ່ມການບັນທຶກ"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ບັນທຶກສຽງ"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ສຽງອຸປະກອນ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"ສຽງຈາກອຸປະກອນຂອງທ່ານ ເຊັ່ນ: ສຽງເພງ, ສຽງລົມໂທລະສັບ ແລະ ສຽງຣິງໂທນ"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ບໍລິການທີ່ສະໜອງຄວາມສາມາດນີ້ຈະມີສິດເຂົ້າເຖິງຂໍ້ມູນທັງໝົດທີ່ປາກົດຢູ່ໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຈາກອຸປະກອນຂອງທ່ານໃນເວລາບັນທຶກ ຫຼື ສົ່ງສັນຍານໜ້າຈໍ. ນີ້ຮວມເຖິງຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຮູບ, ຂໍ້ຄວາມ ແລະ ສຽງທີ່ທ່ານຫຼິ້ນ."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ເລີ່ມການບັນທຶກ ຫຼື ການສົ່ງສັນຍານໜ້າຈໍບໍ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"ເລີ່ມການບັນທຶກ ຫຼື ການສົ່ງສັນຍານໜ້າຈໍກັບ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ບໍ?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"ອະນຸຍາດໃຫ້ <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ແບ່ງປັນ ຫຼື ບັນທຶກບໍ?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"ທົງໝົດໜ້າຈໍ"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"ແອັບດຽວ"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"ເມື່ອທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ມີສິດເຂົ້າເຖິງສິ່ງທີ່ເຫັນໄດ້ໃນໜ້າຈໍຂອງທ່ານ ຫຼື ຫຼິ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ດັ່ງນັ້ນໃຫ້ລະມັດລະວັງເລື່ອງລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ ຫຼື ຂໍ້ມູນທີ່ລະອຽດອ່ອນອື່ນໆ."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"ໃນຕອນທີ່ທ່ານກຳລັງແບ່ງປັນ, ບັນທຶກ ຫຼື ສົ່ງສັນຍານແອັບ, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ມີສິດເຂົ້າເຖິງສິ່ງທີ່ສະແດງ ຫຼື ຫຼິ້ນຢູ່ໃນແອັບນັ້ນ. ດັ່ງນັ້ນໃຫ້ລະມັດລະວັງກ່ຽວກັບລະຫັດຜ່ານ, ລາຍລະອຽດການຈ່າຍເງິນ, ຂໍ້ຄວາມ ຫຼື ຂໍ້ມູນທີ່ລະອຽດອ່ອນອື່ນໆ."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ສືບຕໍ່"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"ແບ່ງປັນ ຫຼື ບັນທຶກແອັບ"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ລຶບລ້າງທັງໝົດ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ຈັດການ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ປະຫວັດ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index fd9c7cc..8e548b6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Šiuo metu rodomas ekrano įrašymo sesijos pranešimas"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Pradėti įrašymą?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Įrašant „Android“ sistema gali fiksuoti bet kokią neskelbtiną informaciją, rodomą ekrane ar leidžiamą įrenginyje. Tai apima slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir garso įrašus."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Įrašyti visą ekraną"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Įrašyti vieną programą"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Kai įrašote, „Android“ gali pasiekti viską, kas rodoma ekrane ar leidžiama įrenginyje. Todėl būkite atsargūs su slaptažodžiais, išsamia mokėjimo metodo informacija, pranešimais ar kita neskelbtina informacija."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Kai įrašote programą „Android“ gali pasiekti viską, kas rodoma ar leidžiama programoje. Todėl būkite atsargūs su slaptažodžiais, išsamia mokėjimo metodo informacija, pranešimais ar kita neskelbtina informacija."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Pradėti įrašymą"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Įrašyti garsą"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Įrenginio garsas"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Garsas iš jūsų įrenginio, pvz., muzika, skambučiai ir skambėjimo tonai"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Šią funkciją teikianti paslauga galės pasiekti visą informaciją, matomą ekrane ir leidžiamą iš įrenginio įrašant ar perduodant turinį. Tai apima įvairią informaciją, pvz., slaptažodžius, išsamią mokėjimo informaciją, nuotraukas, pranešimus ir leidžiamus garso įrašus."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Pradėti įrašyti ar perduoti turinį?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Pradėti įrašyti ar perduoti turinį naudojant „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Leisti „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ bendrinti ar įrašyti?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Visas ekranas"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Viena programa"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Kai bendrinate, įrašote ar perduodate turinį, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ gali pasiekti viską, kas rodoma ekrane ar leidžiama įrenginyje. Todėl būkite atsargūs su slaptažodžiais, išsamia mokėjimo metodo informacija, pranešimais ar kita neskelbtina informacija."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kai bendrinate, įrašote ar perduodate turinį, „<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>“ gali pasiekti viską, kas rodoma ar leidžiama programoje. Todėl būkite atsargūs su slaptažodžiais, išsamia mokėjimo metodo informacija, pranešimais ar kita neskelbtina informacija."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Tęsti"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Programos bendrinimas ar įrašymas"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Viską išvalyti"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Tvarkyti"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 44e5507..9cb8bfd 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Aktīvs paziņojums par ekrāna ierakstīšanas sesiju"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Vai sākt ierakstīšanu?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Ierakstīšanas laikā Android sistēmā var tikt tverta jebkura sensitīvā informācija, kas ir redzama jūsu ekrānā vai tiek atskaņota jūsu ierīcē. Šī informācija ir paroles, maksājumu informācija, fotoattēli, ziņojumi un audio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Ierakstīt audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Ierīces audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Skaņa no jūsu ierīces, piemēram, mūzika, sarunas un zvana signāli"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Pakalpojums, kas nodrošina šo funkciju, iegūs piekļuvi visai informācijai, kas ierakstīšanas vai apraides laikā tiks rādīta jūsu ekrānā vai atskaņota jūsu ierīcē. Atļauja attiecas uz tādu informāciju kā paroles, maksājumu informācija, fotoattēli, ziņojumi un jūsu atskaņotais audio saturs."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vai vēlaties sākt ierakstīšanu/apraidi?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vai vēlaties sākt ierakstīšanu vai apraidi, izmantojot lietotni <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Dzēst visu"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Pārvaldīt"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Vēsture"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 8b8753e..de9e82c7 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Тековно известување за сесија за снимање на екранот"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Да се започне со снимање?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"При снимањето, системот Android може да ги сними сите чувствителни податоци што се видливи на вашиот екран или пуштени на уредот. Ова вклучува лозинки, податоци за плаќање, фотографии, пораки и аудио."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Снимај го целиот екран"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Снимај една апликација"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Додека снимате, Android има пристап до сѐ што е видливо на вашиот екран или пуштено на вашиот уред. Затоа, бидете внимателни со лозинки, детали за плаќање, пораки или други чувствителни податоци."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Додека снимате апликација, Android има пристап до сѐ што се прикажува или пушта на таа апликација. Затоа, бидете внимателни со лозинки, детали за плаќање, пораки или други чувствителни податоци."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Започни со снимање"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Снимај аудио"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Аудио од уредот"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук од вашиот уред, како на пр., музика, повици и мелодии"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услугата што ја обезбедува функцијава ќе има пристап до сите податоци што се видливи на екранот или пуштени од вашиот уред додека се снима или емитува. Ова вклучува податоци како лозинките, деталите за плаќање, фотографиите, пораките и аудиото што го пуштате."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Да почне снимање или емитување?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Да почне снимање или емитување со <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Да ѝ се дозволи на <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> да споделува или снима?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Цел екран"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Една апликација"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Кога споделувате, снимате или емитувате, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има пристап до сѐ што е видливо на вашиот екран или пуштено на вашиот уред. Затоа, бидете внимателни со лозинки, детали за плаќање, пораки или други чувствителни податоци."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Кога споделувате, снимате или емитувате апликација, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има пристап до сѐ што се прикажува или пушта на таа апликација. Затоа, бидете внимателни со лозинки, детали за плаќање, пораки или други чувствителни податоци."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Продолжи"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Споделете или снимете апликација"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Избриши сѐ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Управувајте"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 532ded7..bf1c262 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ഒരു സ്ക്രീൻ റെക്കോർഡിംഗ് സെഷനായി നിലവിലുള്ള അറിയിപ്പ്"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"റെക്കോർഡിംഗ് ആരംഭിക്കണോ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"റെക്കോർഡ് ചെയ്യുമ്പോൾ, നിങ്ങളുടെ സ്‌ക്രീനിൽ ദൃശ്യമാകുന്നതോ ഉപകരണത്തിൽ പ്ലേ ചെയ്യുന്നതോ ആയ ഏത് തന്ത്രപ്രധാന വിവരങ്ങളും Android സിസ്റ്റത്തിന് പകർത്താനാവും. പാസ്‍വേഡുകൾ, പേയ്‌മെന്റ് വിവരം, ഫോട്ടോകൾ, സന്ദേശങ്ങൾ, ഓഡിയോ എന്നിവ ഇതിൽ ഉൾപ്പെടുന്നു."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ഉപകരണത്തിന്റെ ഓഡിയോ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"സംഗീതം, കോളുകൾ, റിംഗ്‌ടോണുകൾ എന്നിവപോലെ നിങ്ങളുടെ ഉപകരണത്തിൽ നിന്നുള്ള ശബ്ദം"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"റെക്കോർഡ് ചെയ്യുമ്പോഴോ കാസ്‌റ്റ് ചെയ്യുമ്പോഴോ നിങ്ങളുടെ ഉപകരണത്തിൽ നിന്ന് പ്ലേ ചെയ്യുന്നതോ നിങ്ങളുടെ സ്‌ക്രീനിൽ ദൃശ്യമാകുന്നതോ ആയ എല്ലാ വിവരങ്ങളിലേക്കും ഈ ഫംഗ്‌ഷൻ ലഭ്യമാക്കുന്ന സേവനത്തിന് ആക്‌സസ് ഉണ്ടായിരിക്കും. നിങ്ങൾ പ്ലേ ചെയ്യുന്ന ഓഡിയോ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ, പേയ്‌മെന്റ് വിശദാംശങ്ങൾ, പാസ്‌വേഡുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഇതിൽ ഉൾപ്പെടുന്നു."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"റെക്കോർഡ് ചെയ്യൽ അല്ലെങ്കിൽ കാസ്റ്റ് ചെയ്യൽ ആരംഭിക്കണോ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ഉപയോഗിച്ച് റെക്കോർഡ് ചെയ്യൽ അല്ലെങ്കിൽ കാസ്‌റ്റ് ചെയ്യൽ ആരംഭിക്കണോ?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"എല്ലാം മായ്‌ക്കുക"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"മാനേജ് ചെയ്യുക"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ചരിത്രം"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 985a0e6..6805916 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Дэлгэц бичих горимын үргэлжилж буй мэдэгдэл"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Бичлэгийг эхлүүлэх үү?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Бичих үед Андройд систем нь таны дэлгэц дээр харагдах эсвэл төхөөрөмж дээрээ тоглуулсан аливаа эмзэг мэдээллийг авах боломжтой. Үүнд нууц үг, төлбөрийн мэдээлэл, зураг, мессеж болон аудио багтана."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Бүтэн дэлгэцийг бичих"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Нэг аппыг бичих"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Таныг бичиж байх үед Android нь таны дэлгэц дээр харагдаж буй эсвэл төхөөрөмж дээр тоглуулж буй аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж эсвэл бусад эмзэг мэдээлэлд болгоомжтой хандаарай."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Таныг апп бичиж байх үед Android нь тухайн апп дээр харуулж эсвэл тоглуулж буй аливаа зүйлд хандах эрхтэй."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Бичиж эхлэх"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Аудио бичих"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Төхөөрөмжийн аудио"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Хөгжим, дуудлага болон хонхны ая зэрэг таны төхөөрөмжийн дуу"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Энэ функцийг ажиллуулж байгаа үйлчилгээ нь бичлэг хийх эсвэл дамжуулах үед таны дэлгэц дээр харагдах эсвэл таны төхөөрөмжөөс тоглуулах бүх мэдээлэлд хандах боломжтой байна. Үүнд нууц үг, төлбөрийн дэлгэрэнгүй, зураг болон таны тоглуулдаг аудио зэрэг мэдээлэл багтана."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Бичлэг хийх эсвэл дамжуулахыг эхлүүлэх үү?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-тай бичлэг хийж эсвэл дамжуулж эхлэх үү?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>-д хуваалцах эсвэл бичихийг зөвшөөрөх үү?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Бүтэн дэлгэц"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Нэг апп"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Таныг хуваалцаж, бичиж эсвэл дамжуулж байх үед <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь таны дэлгэц дээр харагдаж буй аливаа зүйл эсвэл төхөөрөмж дээр тань тоглуулж буй зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж эсвэл бусад эмзэг мэдээлэлд болгоомжтой хандаарай."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Таныг хуваалцаж, бичиж эсвэл дамжуулж байх үед <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> нь тухайн апп дээр харуулсан эсвэл тоглуулсан аливаа зүйлд хандах эрхтэй. Тиймээс нууц үг, төлбөрийн дэлгэрэнгүй, мессеж эсвэл бусад эмзэг мэдээлэлд болгоомжтой хандаарай."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Үргэлжлүүлэх"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Хуваалцах эсвэл бичих апп"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Бүгдийг арилгах"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Удирдах"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Түүх"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 6a2276a..f7b8ef0 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"स्क्रीन रेकॉर्ड सत्रासाठी सुरू असलेली सूचना"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"रेकॉर्डिंग सुरू करायचे आहे का?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"रेकॉर्डिंग करताना, Android सिस्टीम तुमच्या स्क्रीनवर दिसणारी किंवा तुमच्या डिव्हाइसवर प्ले केलेली कोणतीही संवेदनशील माहिती कॅप्चर करू शकते. यात पासवर्ड, पेमेंट माहिती, फोटो, मेसेज आणि ऑडिओचा समावेश आहे."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ऑडिओ रेकॉर्ड करा"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिव्हाइस ऑडिओ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"तुमच्या डिव्हाइसवरील आवाज, जसे की संगीत, कॉल आणि रिंगटोन"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"हे कार्य पुरवणाऱ्या सेवेस तुमच्या स्क्रीनवर दृश्यमान असलेल्या किंवा रेकॉर्ड किंवा कास्ट करताना तुमच्या डिव्हाइसमधून प्ले केलेल्या सर्व माहितीचा अ‍ॅक्सेस असेल. यामध्ये पासवर्ड, पेमेंट तपशील, फोटो, मेसेज आणि तुम्ही प्ले केलेला ऑडिओ यासारख्या माहितीचा समावेश असतो."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकॉर्ड करणे किंवा कास्ट करणे सुरू करायचे का ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ने रेकॉर्ड करणे किंवा कास्ट करणे सुरू करायचे का?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सर्व साफ करा"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8a9a8d6..e6dcbbb 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pemberitahuan breterusan untuk sesi rakaman skrin"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Mula Merakam?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Semasa merakam, Sistem Android dapat menangkap mana-mana maklumat sensitif yang kelihatan pada skrin anda atau yang dimainkan pada peranti anda. Ini termasuklah kata laluan, maklumat pembayaran, foto, mesej dan audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Rakam seluruh skrin"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Rakam satu apl"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Apabila anda merakam, Android mempunyai akses kepada apa-apa yang boleh dilihat pada skrin anda atau dimainkan pada peranti anda. Jadi berhati-hati dengan kata laluan, butiran pembayaran, mesej atau maklumat sensitif lain."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Apabila anda merakam apl, Android mempunyai akses kepada apa-apa yang dipaparkan atau dimainkan pada apl tersebut. Jadi berhati-hati dengan kata laluan, butiran pembayaran, mesej atau maklumat sensitif lain."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Mulakan rakaman"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Rakam audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio peranti"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Bunyi daripada peranti anda, seperti muzik, panggilan dan nada dering"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Perkhidmatan yang menyediakan fungsi ini akan mempunyai akses kepada semua maklumat yang kelihatan pada skrin anda atau dimainkan daripada peranti anda semasa merakam atau membuat penghantaran. Ini termasuklah maklumat seperti kata laluan, butiran pembayaran, foto, mesej dan audio yang anda mainkan."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Mulakan rakaman atau penghantaran?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Mulakan rakaman atau penghantaran dengan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Benarkan <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> berkongsi atau merakam?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Seluruh skrin"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Satu apl"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Apabila anda berkongsi, merakam atau menghantar, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mempunyai akses kepada apa-apa yang boleh dilihat pada skrin anda atau dimainkan pada peranti anda. Jadi berhati-hati dengan kata laluan, butiran pembayaran, mesej atau maklumat sensitif lain."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Apabila anda berkongsi, merakam atau menghantar apl, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> mempunyai akses kepada apa-apa yang dipaparkan atau dimainkan pada apl tersebut. Jadi berhati-hati dengan kata laluan, butiran pembayaran, mesej atau maklumat sensitif lain."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Teruskan"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Kongsi atau rakam apl"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Kosongkan semua"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Urus"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Sejarah"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index ddfb404..a874e45 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ဖန်သားပြင် ရိုက်ကူးသည့် စက်ရှင်အတွက် ဆက်တိုက်လာနေသော အကြောင်းကြားချက်"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"စတင် ရိုက်ကူးမလား။"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ရိုက်ကူးနေစဉ်အတွင်း Android စနစ်သည် သင့်ဖန်သားပြင်ပေါ်တွင် မြင်နိုင်သော (သို့) သင့်စက်ပစ္စည်းတွင် ဖွင့်ထားသော အရေးကြီးသည့် အချက်အလက်များကို ရိုက်ယူနိုင်သည်။ ၎င်းတွင် စကားဝှက်၊ ငွေပေးချေမှု အချက်အလက်၊ ဓာတ်ပုံ၊ မက်ဆေ့ဂျ်နှင့် အသံများ ပါဝင်သည်။"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"အသံဖမ်းရန်"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"စက်ပစ္စည်းအသံ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"သီချင်း၊ ဖုန်းခေါ်ဆိုမှုနှင့် ဖုန်းမြည်သံကဲ့သို့ သင့်စက်ပစ္စည်းမှ အသံ"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ဤဝန်ဆောင်မှုသည် ရိုက်ကူးဖမ်းယူနေစဉ် (သို့) ကာစ်လုပ်နေစဉ်အတွင်း သင့်ဖန်သားပြင်တွင် မြင်ရသော (သို့) သင့်စက်တွင် ဖွင့်ထားသော အချက်အလက်အားလုံးကို ကြည့်နိုင်ပါမည်။ ၎င်းတွင် စကားဝှက်များ၊ ငွေပေးချေမှုအသေးစိတ်များ၊ ဓာတ်ပုံများ၊ မက်ဆေ့ဂျ်များနှင့် သင်ဖွင့်သည့်အသံကဲ့သို့သော အချက်အလက်များ ပါဝင်သည်။"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ရိုက်ကူးဖမ်းယူခြင်း (သို့) ကာစ်လုပ်ခြင်း စတင်မလား။"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> နှင့် ဖမ်းယူခြင်း သို့မဟုတ် ကာစ်လုပ်ခြင်း စတင်မလား။"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"အားလုံးရှင်းရန်"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 4e97b48..6dd9d8f 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Vedvarende varsel for et skjermopptak"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Vil du starte et opptak?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Under opptak kan Android-systemet registrere all sensitiv informasjon som er synlig på skjermen eller spilles av på enheten. Dette inkluderer passord, betalingsinformasjon, bilder, meldinger og lyd."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Spill inn lyd"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Enhetslyd"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Lyd fra enheten, f.eks. musikk, samtaler og ringelyder"</string>
@@ -233,13 +243,13 @@
     <string name="quick_settings_internet_label" msgid="6603068555872455463">"Internett"</string>
     <string name="quick_settings_networks_available" msgid="1875138606855420438">"Tilgjengelige nettverk"</string>
     <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Nettverk er utilgjengelige"</string>
-    <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ingen tilgjengelige Wi-Fi-nettverk"</string>
+    <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Ingen tilgjengelige Wifi-nettverk"</string>
     <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Slår på …"</string>
     <string name="quick_settings_cast_title" msgid="2279220930629235211">"Skjermcasting"</string>
     <string name="quick_settings_casting" msgid="1435880708719268055">"Casting"</string>
     <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Enhet uten navn"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Ingen enheter er tilgjengelige"</string>
-    <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wi-Fi er ikke tilkoblet"</string>
+    <string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Wifi er ikke tilkoblet"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
     <string name="quick_settings_inversion_label" msgid="3501527749494755688">"Fargeinvertering"</string>
     <string name="quick_settings_color_correction_label" msgid="5636617913560474664">"Fargekorrigering"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Tjenesten som leverer denne funksjonen, får tilgang til all informasjon som er synlig på skjermen din, eller som spilles av fra enheten når du tar opp eller caster. Dette inkluderer informasjon som passord, betalingsopplysninger, bilder, meldinger og lyd du spiller av."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vil du starte opptak eller casting?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vil du starte opptak eller casting med <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Fjern alt"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Logg"</string>
@@ -704,7 +728,7 @@
     <string name="mobile_data" msgid="4564407557775397216">"Mobildata"</string>
     <string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
-    <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi er av"</string>
+    <string name="wifi_is_off" msgid="5389597396308001471">"Wifi er av"</string>
     <string name="bt_is_off" msgid="7436344904889461591">"Bluetooth er av"</string>
     <string name="dnd_is_off" msgid="3185706903793094463">"Ikke forstyrr er av"</string>
     <string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Ikke forstyrr ble slått på av en automatisk regel (<xliff:g id="ID_1">%s</xliff:g>)."</string>
@@ -713,7 +737,7 @@
     <string name="running_foreground_services_title" msgid="5137313173431186685">"Apper kjører i bakgrunnen"</string>
     <string name="running_foreground_services_msg" msgid="3009459259222695385">"Trykk for detaljer om batteri- og databruk"</string>
     <string name="mobile_data_disable_title" msgid="5366476131671617790">"Vil du slå av mobildata?"</string>
-    <string name="mobile_data_disable_message" msgid="8604966027899770415">"Du får ikke tilgang til data eller internett via <xliff:g id="CARRIER">%s</xliff:g>. Internett er bare tilgjengelig via Wi-Fi."</string>
+    <string name="mobile_data_disable_message" msgid="8604966027899770415">"Du får ikke tilgang til data eller internett via <xliff:g id="CARRIER">%s</xliff:g>. Internett er bare tilgjengelig via Wifi."</string>
     <string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"operatøren din"</string>
     <string name="touch_filtered_warning" msgid="8119511393338714836">"Fordi en app skjuler tillatelsesforespørselen, kan ikke Innstillinger bekrefte svaret ditt."</string>
     <string name="slice_permission_title" msgid="3262615140094151017">"Vil du tillate at <xliff:g id="APP_0">%1$s</xliff:g> viser <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt?"</string>
@@ -914,10 +938,10 @@
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string>
-    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wi-Fi kobles ikke til automatisk inntil videre"</string>
+    <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Wifi kobles ikke til automatisk inntil videre"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
     <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"For å bytte nettverk, koble fra Ethernet"</string>
-    <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wi-Fi-nettverk når som helst – også når Wi-Fi er slått av. Du kan endre dette i innstillingene for wifi-skanning. "<annotation id="link">"Endre"</annotation></string>
+    <string name="wifi_scan_notify_message" msgid="3753839537448621794">"For å forbedre brukeropplevelsen på enheten kan apper og tjenester søke etter Wifi-nettverk når som helst – også når Wifi er slått av. Du kan endre dette i innstillingene for wifi-skanning. "<annotation id="link">"Endre"</annotation></string>
     <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Slå av flymodus"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vil legge til denne brikken i Hurtiginnstillinger"</string>
     <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Legg til brikke"</string>
@@ -962,6 +986,6 @@
     <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Endre utgang"</string>
     <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ukjent"</string>
     <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d. MMM"</string>
-    <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"t:mm"</string>
-    <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"tt:mm"</string>
+    <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string>
+    <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index caeceb4..2362b40 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"कुनै स्क्रिन रेकर्ड गर्ने सत्रका लागि चलिरहेको सूचना"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"रेकर्ड गर्न थाल्ने हो?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"रेकर्ड गर्दा, Android सिस्टमले तपाईंको स्क्रिनमा देखिने वा तपाईंको डिभाइसमा प्ले गरिने सबै संवेदनशील जानकारी रेकर्ड गर्न सक्छ। यो जानकारीमा पासवर्ड, भुक्तानीसम्बन्धी जानकारी, फोटो, सन्देश र अडियो समावेश हुन्छ।"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"अडियो रेकर्ड गरियोस्"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"डिभाइसको अडियो"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"तपाईंको डिभाइसका सङ्गीत, कल र रिङटोन जस्ता साउन्ड"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"यो कार्य गर्ने सेवाले तपाईंको स्क्रिनमा देख्न सकिने सबै जानकारी अथवा रेकर्ड वा कास्ट गर्दा तपाईंको डिभाइसबाट प्ले गरिएका कुरा हेर्न तथा प्रयोग गर्न सक्छ। यसले हेर्न तथा प्रयोग गर्न सक्ने कुरामा पासवर्ड, भुक्तानीका विवरण, फोटो, सन्देश र तपाईंले प्ले गर्ने अडियो कुराहरू समावेश हुन सक्छन्।"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> मार्फत रेकर्ड गर्न वा cast गर्न थाल्ने हो?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"सबै हटाउनुहोस्"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थित गर्नुहोस्"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 1cad1bc..641c128 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Doorlopende melding voor een schermopname-sessie"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Opname starten?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Tijdens de opname kan het Android-systeem gevoelige informatie opnemen die zichtbaar is op je scherm of wordt afgespeeld op je apparaat, waaronder wachtwoorden, betalingsgegevens, foto\'s, berichten en audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Volledig scherm opnemen"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Eén app opnemen"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Als je opneemt, heeft Android toegang tot alles dat zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Wees daarom voorzichtig met wachtwoorden, betalingsgegevens, berichten en andere gevoelige informatie."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Als je een app opneemt, heeft Android toegang tot alles dat wordt getoond of afgespeeld in die app. Wees daarom voorzichtig met wachtwoorden, betalingsgegevens, berichten en andere gevoelige informatie."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Opname starten"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Audio opnemen"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio van apparaat"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Geluid van je apparaat, zoals muziek, gesprekken en ringtones"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"De service die deze functie levert, krijgt tijdens het opnemen of casten toegang tot alle informatie die op je scherm te zien is of op je apparaat wordt afgespeeld. Dit omvat informatie zoals wachtwoorden, betalingsgegevens, foto\'s, berichten en audio die je afspeelt."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Beginnen met opnemen of casten?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Beginnen met opnemen of casten met <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Toestaan dat <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> deelt of opneemt?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Volledig scherm"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Eén app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Als je deelt, opneemt of cast, heeft <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot alles dat zichtbaar is op je scherm of wordt afgespeeld op je apparaat. Wees daarom voorzichtig met wachtwoorden, betalingsgegevens, berichten en andere gevoelige informatie."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Als je deelt, opneemt of cast, heeft <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> toegang tot alles dat wordt getoond of afgespeeld in die app. Wees daarom voorzichtig met wachtwoorden, betalingsgegevens, berichten en andere gevoelige informatie."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Doorgaan"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"App delen of opnemen"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Alles wissen"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Beheren"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Geschiedenis"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index a5983de..01d0d9f 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ଏକ ସ୍କ୍ରି‍ନ୍‍ ରେକର୍ଡ୍‍ ସେସନ୍‍ ପାଇଁ ଚାଲୁଥିବା ବିଜ୍ଞପ୍ତି"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ରେକର୍ଡିଂ ଆରମ୍ଭ କରିବେ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ରେକର୍ଡିଂ ସମୟରେ, Android ସିଷ୍ଟମ୍ ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଦେଖାଯାଉଥିବା ବା ଆପଣଙ୍କ ଡିଭାଇସରେ ଚାଲୁଥିବା ଯେ କୌଣସି ସମ୍ବେଦନଶୀଳ ସୂଚନାକୁ କ୍ୟାପଚର୍ କରିପାରିବ। ଏଥିରେ ପାସୱାର୍ଡ, ପେମେଣ୍ଟ ସୂଚନା, ଫଟୋ, ମେସେଜ ଏବଂ ଅଡିଓ ଅନ୍ତର୍ଭୁକ୍ତ।"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ଡିଭାଇସ୍ ଅଡିଓ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"ଆପଣଙ୍କ ଡିଭାଇସରୁ ସାଉଣ୍ଡ, ଯେପରିକି ସଙ୍ଗୀତ, କଲ୍ ଏବଂ ରିଂଟୋନଗୁଡ଼ିକ"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ବେଳେ ଆପଣଙ୍କର ଡିଭାଇସରେ ଦେଖାଯାଉଥିବା ବା ଆପଣଙ୍କ ଡିଭାଇସରୁ ପ୍ଲେ କରାଯାଉଥିବା ସବୁ ସୂଚନାକୁ ଏହି ଫଙ୍କସନ୍ ପ୍ରଦାନ କରୁଥିବା ସେବାର ଆକ୍ସେସ୍ ରହିବ। ପାସ୍‌ୱାର୍ଡ, ପେମେଣ୍ଟ ବିବରଣୀ, ଫଟୋ, ମେସେଜ୍ ଏବଂ ଆପଣ ଚଲାଉଥିବା ଅଡିଓ ପରି ସୂଚନା ଏଥିରେ ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି।"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ଆରମ୍ଭ କରିବେ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ସହ ରେକର୍ଡିଂ ବା କାଷ୍ଟିଂ ଆରମ୍ଭ କରିବେ?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ସମସ୍ତ ଖାଲି କରନ୍ତୁ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ପରିଚାଳନା କରନ୍ତୁ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ଇତିହାସ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 0c78e89..e9f4cf9 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"ਕਿਸੇ ਸਕ੍ਰੀਨ ਰਿਕਾਰਡ ਸੈਸ਼ਨ ਲਈ ਚੱਲ ਰਹੀ ਸੂਚਨਾ"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ਕੀ ਰਿਕਾਰਡਿੰਗ ਸ਼ੁਰੂ ਕਰਨੀ ਹੈ?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ਰਿਕਾਰਡਿੰਗ ਕਰਨ ਵੇਲੇ, Android ਸਿਸਟਮ ਕੋਈ ਵੀ ਅਜਿਹੀ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਕੈਪਚਰ ਕਰ ਸਕਦਾ ਹੈ ਜੋ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੈ ਜਾਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡ, ਭੁਗਤਾਨ ਵੇਰਵੇ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹੇ ਅਤੇ ਆਡੀਓ ਸ਼ਾਮਲ ਹਨ।"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ਆਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"ਡੀਵਾਈਸ ਆਡੀਓ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀ ਧੁਨੀ, ਜਿਵੇਂ ਕਿ ਸੰਗੀਤ, ਕਾਲਾਂ ਅਤੇ ਰਿੰਗਟੋਨਾਂ"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"ਇਹ ਫੰਕਸ਼ਨ ਪ੍ਰਦਾਨ ਕਰਨ ਵਾਲੀ ਸੇਵਾ ਕੋਲ ਸਾਰੀ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਹੋਵੇਗੀ ਜੋ ਕਿ ਤੁਹਾਡੀ ਸਕ੍ਰੀਨ \'ਤੇ ਦਿਖਣਯੋਗ ਹੁੰਦੀ ਹੈ ਜਾਂ ਰਿਕਾਰਡ ਜਾਂ ਕਾਸਟ ਕਰਨ ਵੇਲੇ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਚਲਾਈ ਜਾਂਦੀ ਹੈ। ਇਸ ਵਿੱਚ ਪਾਸਵਰਡ, ਭੁਗਤਾਨ ਵੇਰਵੇ, ਫ਼ੋਟੋਆਂ, ਸੁਨੇਹੇ ਅਤੇ ਤੁਹਾਡੇ ਵੱਲੋਂ ਚਲਾਏ ਆਡੀਓ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ।"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ਕੀ ਰਿਕਾਰਡ ਜਾਂ ਕਾਸਟ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ਨਾਲ ਰਿਕਾਰਡਿੰਗ ਜਾਂ ਕਾਸਟ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨਾ ਹੈ?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 063ffbf..dad40e1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Stałe powiadomienie o sesji rejestrowania zawartości ekranu"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Rozpocząć nagrywanie?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Podczas nagrywania system Android może rejestrować wszelkie informacje poufne wyświetlane na ekranie lub odtwarzane na urządzeniu. Dotyczy to m.in. haseł, szczegółów płatności, zdjęć, wiadomości i odtwarzanych dźwięków."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Nagraj dźwięk"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Dźwięki z urządzenia"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Dźwięki odtwarzane na urządzeniu, na przykład muzyka, połączenia i dzwonki"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Podczas nagrywania i przesyłania usługa udostępniająca tę funkcję będzie miała dostęp do wszystkich informacji widocznych na ekranie lub odtwarzanych na urządzeniu. Dotyczy to m.in. haseł, szczegółów płatności, zdjęć, wiadomości i odtwarzanych dźwięków."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Rozpocząć nagrywanie lub przesyłanie?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Rozpocząć nagrywanie lub przesyłanie za pomocą aplikacji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Usuń wszystkie"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Zarządzaj"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index f85ab52..218fd95 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Iniciar gravação?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durante a gravação, o sistema Android pode capturar informações confidenciais visíveis na tela ou tocadas no dispositivo. Isso inclui senhas, informações de pagamento, fotos, mensagens e áudio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Gravar a tela inteira"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Gravar um app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Enquanto você grava, o Android tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Enquanto você grava um app, o Android tem acesso a todas as informações visíveis ou reproduzidas no app. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Iniciar gravação"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Gravar áudio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Áudio do dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sons do dispositivo, como música, chamadas e toques"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudio."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Permitir que o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> compartilhe ou grave a tela?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Tela cheia"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Um único app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Quando você compartilha, grava ou transmite a tela, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando você compartilha, grava ou transmite um app, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartilhar ou gravar um app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
index bc7efe6..ebe67d8 100644
--- a/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/tiles_states_strings.xml
@@ -138,8 +138,8 @@
   </string-array>
   <string-array name="tile_states_cameratoggle">
     <item msgid="6680671247180519913">"Indisponível"</item>
-    <item msgid="4765607635752003190">"Desativada"</item>
-    <item msgid="1697460731949649844">"Ativada"</item>
+    <item msgid="4765607635752003190">"Desligada"</item>
+    <item msgid="1697460731949649844">"Ligada"</item>
   </string-array>
   <string-array name="tile_states_mictoggle">
     <item msgid="6895831614067195493">"Indisponível"</item>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a33552b..9110aa0 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação persistente de uma sessão de gravação de ecrã"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Iniciar a gravação?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Enquanto estiver a gravar, o sistema Android pode capturar quaisquer informações confidenciais que estejam visíveis no ecrã ou que sejam reproduzidas no dispositivo. Isto inclui palavras-passe, informações de pagamento, fotos, mensagens e áudio."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Gravar áudio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Áudio do dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"O som do dispositivo, como música, chamadas e toques."</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que fornece esta função terá acesso a todas as informações que estiverem visíveis no ecrã ou que forem reproduzidas a partir do dispositivo durante a gravação ou transmissão. Isto inclui informações como palavras-passe, detalhes de pagamentos, fotos, mensagens e áudio reproduzido."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Começar a gravar ou a transmitir?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Começar a gravar ou a transmitir com a app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gerir"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
@@ -474,7 +498,7 @@
     <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Tocar para abrir"</string>
     <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"A atualizar"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Desbloquear para utilizar"</string>
-    <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente novamente mais tarde."</string>
+    <string name="wallet_error_generic" msgid="257704570182963611">"Ocorreu um problema ao obter os seus cartões. Tente mais tarde."</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Definições do ecrã de bloqueio"</string>
     <string name="qr_code_scanner_title" msgid="5290201053875420785">"Leia o código QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Perfil de trabalho"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
index 0a01020..bda7473 100644
--- a/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/tiles_states_strings.xml
@@ -138,8 +138,8 @@
   </string-array>
   <string-array name="tile_states_cameratoggle">
     <item msgid="6680671247180519913">"Indisponível"</item>
-    <item msgid="4765607635752003190">"Desligado"</item>
-    <item msgid="1697460731949649844">"Ligado"</item>
+    <item msgid="4765607635752003190">"Desligada"</item>
+    <item msgid="1697460731949649844">"Ligada"</item>
   </string-array>
   <string-array name="tile_states_mictoggle">
     <item msgid="6895831614067195493">"Indisponível"</item>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index f85ab52..218fd95 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificação contínua para uma sessão de gravação de tela"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Iniciar gravação?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Durante a gravação, o sistema Android pode capturar informações confidenciais visíveis na tela ou tocadas no dispositivo. Isso inclui senhas, informações de pagamento, fotos, mensagens e áudio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Gravar a tela inteira"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Gravar um app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Enquanto você grava, o Android tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Enquanto você grava um app, o Android tem acesso a todas as informações visíveis ou reproduzidas no app. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Iniciar gravação"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Gravar áudio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Áudio do dispositivo"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sons do dispositivo, como música, chamadas e toques"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"O serviço que oferece essa função terá acesso a todas as informações visíveis na tela ou reproduzidas durante uma gravação ou transmissão. Isso inclui senhas, detalhes de pagamento, fotos, mensagens e áudio."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Iniciar gravação ou transmissão?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Iniciar gravação ou transmissão com o app <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Permitir que o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> compartilhe ou grave a tela?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Tela cheia"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Um único app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Quando você compartilha, grava ou transmite a tela, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Quando você compartilha, grava ou transmite um app, o <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> tem acesso a todas as informações visíveis na tela ou reproduzidas no dispositivo. Tenha cuidado com senhas, detalhes de pagamento, mensagens ou outras informações sensíveis."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Continuar"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Compartilhar ou gravar um app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Limpar tudo"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string>
diff --git a/packages/SystemUI/res/values-pt/tiles_states_strings.xml b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
index bc7efe6..ebe67d8 100644
--- a/packages/SystemUI/res/values-pt/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-pt/tiles_states_strings.xml
@@ -138,8 +138,8 @@
   </string-array>
   <string-array name="tile_states_cameratoggle">
     <item msgid="6680671247180519913">"Indisponível"</item>
-    <item msgid="4765607635752003190">"Desativada"</item>
-    <item msgid="1697460731949649844">"Ativada"</item>
+    <item msgid="4765607635752003190">"Desligada"</item>
+    <item msgid="1697460731949649844">"Ligada"</item>
   </string-array>
   <string-array name="tile_states_mictoggle">
     <item msgid="6895831614067195493">"Indisponível"</item>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bd920e2..f82954e 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -21,7 +21,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="4811759950673118541">"UI sistem"</string>
     <string name="battery_low_title" msgid="5319680173344341779">"Activezi Economisirea bateriei?"</string>
-    <string name="battery_low_description" msgid="3282977755476423966">"Mai aveți <xliff:g id="PERCENTAGE">%s</xliff:g> din baterie. Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
+    <string name="battery_low_description" msgid="3282977755476423966">"Mai ai <xliff:g id="PERCENTAGE">%s</xliff:g> din baterie. Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
     <string name="battery_low_intro" msgid="5148725009653088790">"Economisirea bateriei activează Tema întunecată, restricționează activitatea în fundal și amână notificările."</string>
     <string name="battery_low_percent_format" msgid="4276661262843170964">"Procent rămas din baterie: <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
     <string name="invalid_charger_title" msgid="938685362320735167">"Nu se poate realiza încărcarea prin USB"</string>
@@ -36,8 +36,8 @@
     <string name="usb_device_permission_prompt_warn" msgid="2309129784984063656">"Permiți accesul aplicației <xliff:g id="APPLICATION">%1$s</xliff:g> la <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nPermisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
     <string name="usb_audio_device_permission_prompt_title" msgid="4221351137250093451">"Permiți ca <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_audio_device_confirm_prompt_title" msgid="8828406516732985696">"Deschizi <xliff:g id="APPLICATION">%1$s</xliff:g> ca să gestioneze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
-    <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB. Dacă folosiți <xliff:g id="APPLICATION">%1$s</xliff:g> cu acest dispozitiv, acest lucru vă poate împiedica să auziți apeluri, notificări și alarme."</string>
-    <string name="usb_audio_device_prompt" msgid="7944987408206252949">"Dacă folosiți <xliff:g id="APPLICATION">%1$s</xliff:g> cu acest dispozitiv, acest lucru vă poate împiedica să auziți apeluri, notificări și alarme."</string>
+    <string name="usb_audio_device_prompt_warn" msgid="2504972133361130335">"Permisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB. Dacă folosești <xliff:g id="APPLICATION">%1$s</xliff:g> cu acest dispozitiv, acest lucru te poate împiedica să auzi apeluri, notificări și alarme."</string>
+    <string name="usb_audio_device_prompt" msgid="7944987408206252949">"Dacă folosești <xliff:g id="APPLICATION">%1$s</xliff:g> cu acest dispozitiv, acest lucru te poate împiedica să auzi apeluri, notificări și alarme."</string>
     <string name="usb_accessory_permission_prompt" msgid="717963550388312123">"Permiți ca <xliff:g id="APPLICATION">%1$s</xliff:g> să acceseze <xliff:g id="USB_ACCESSORY">%2$s</xliff:g>?"</string>
     <string name="usb_device_confirm_prompt" msgid="4091711472439910809">"Deschizi <xliff:g id="APPLICATION">%1$s</xliff:g> ca să gestioneze <xliff:g id="USB_DEVICE">%2$s</xliff:g>?"</string>
     <string name="usb_device_confirm_prompt_warn" msgid="990208659736311769">"Deschizi <xliff:g id="APPLICATION">%1$s</xliff:g> pentru a gestiona <xliff:g id="USB_DEVICE">%2$s</xliff:g>?\nPermisiunea de înregistrare nu a fost acordată aplicației, dar aceasta poate să înregistreze conținut audio prin intermediul acestui dispozitiv USB."</string>
@@ -53,7 +53,7 @@
     <string name="usb_debugging_allow" msgid="1722643858015321328">"Permite"</string>
     <string name="usb_debugging_secondary_user_title" msgid="7843050591380107998">"Remedierea erorilor prin USB nu este permisă"</string>
     <string name="usb_debugging_secondary_user_message" msgid="3740347841470403244">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor prin USB. Pentru a folosi această funcție, comută la utilizatorul principal."</string>
-    <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Schimbați limba de sistem la <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
+    <string name="hdmi_cec_set_menu_language_title" msgid="1259765420091503742">"Schimbi limba de sistem la <xliff:g id="LANGUAGE">%1$s</xliff:g>?"</string>
     <string name="hdmi_cec_set_menu_language_description" msgid="8176716678074126619">"Alt dispozitiv solicită schimbarea limbii de sistem"</string>
     <string name="hdmi_cec_set_menu_language_accept" msgid="2513689457281009578">"Schimbă limba"</string>
     <string name="hdmi_cec_set_menu_language_decline" msgid="7650721096558646011">"Păstrează limba actuală"</string>
@@ -62,7 +62,7 @@
     <string name="wifi_debugging_always" msgid="2968383799517975155">"Permite întotdeauna în această rețea"</string>
     <string name="wifi_debugging_allow" msgid="4573224609684957886">"Permite"</string>
     <string name="wifi_debugging_secondary_user_title" msgid="2493201475880517725">"Remedierea erorilor wireless nu este permisă"</string>
-    <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor wireless. Pentru a folosi această funcție, comutați la utilizatorul principal."</string>
+    <string name="wifi_debugging_secondary_user_message" msgid="4492383073970079751">"Utilizatorul conectat momentan pe acest dispozitiv nu poate activa remedierea erorilor wireless. Pentru a folosi această funcție, comută la utilizatorul principal."</string>
     <string name="usb_contaminant_title" msgid="894052515034594113">"Portul USB a fost dezactivat"</string>
     <string name="usb_contaminant_message" msgid="7730476585174719805">"Pentru a proteja dispozitivul de lichide sau reziduuri, portul USB este dezactivat și nu va detecta niciun accesoriu.\n\nVei primi o notificare când poți folosi din nou portul USB."</string>
     <string name="usb_port_enabled" msgid="531823867664717018">"Portul USB a fost activat pentru a detecta încărcătoarele și accesoriile"</string>
@@ -74,7 +74,7 @@
     <string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string>
     <string name="screenshot_saved_title" msgid="8893267638659083153">"Captură de ecran salvată"</string>
     <string name="screenshot_failed_title" msgid="3259148215671936891">"Nu s-a putut salva captura de ecran"</string>
-    <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"Pentru a salva captura de ecran, trebuie să deblocați dispozitivul"</string>
+    <string name="screenshot_failed_to_save_user_locked_text" msgid="6156607948256936920">"Pentru a salva captura de ecran, trebuie să deblochezi dispozitivul"</string>
     <string name="screenshot_failed_to_save_unknown_text" msgid="1506621600548684129">"Încearcă să faci din nou o captură de ecran"</string>
     <string name="screenshot_failed_to_save_text" msgid="7232739948999195960">"Nu se poate salva captura de ecran"</string>
     <string name="screenshot_failed_to_capture_text" msgid="7818288545874407451">"Crearea capturilor de ecran nu e permisă de aplicație sau de organizația ta"</string>
@@ -82,7 +82,7 @@
     <string name="screenshot_edit_label" msgid="8754981973544133050">"Editează"</string>
     <string name="screenshot_edit_description" msgid="3333092254706788906">"Editează captura de ecran"</string>
     <string name="screenshot_share_description" msgid="2861628935812656612">"Trimite captura de ecran"</string>
-    <string name="screenshot_scroll_label" msgid="2930198809899329367">"Surprindeți mai mult"</string>
+    <string name="screenshot_scroll_label" msgid="2930198809899329367">"Surprinde mai mult"</string>
     <string name="screenshot_dismiss_description" msgid="4702341245899508786">"Închide captura de ecran"</string>
     <string name="screenshot_preview_description" msgid="7606510140714080474">"Previzualizare a capturii de ecran"</string>
     <string name="screenshot_top_boundary_pct" msgid="2520148599096479332">"Marginea de sus la <xliff:g id="PERCENT">%1$d</xliff:g> %%"</string>
@@ -92,14 +92,24 @@
     <string name="screenrecord_name" msgid="2596401223859996572">"Recorder pentru ecran"</string>
     <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Se procesează înregistrarea"</string>
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Notificare în curs pentru o sesiune de înregistrare a ecranului"</string>
-    <string name="screenrecord_start_label" msgid="1750350278888217473">"Începeți înregistrarea?"</string>
+    <string name="screenrecord_start_label" msgid="1750350278888217473">"Începi înregistrarea?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"În timpul înregistrării, sistemul Android poate captura informațiile sensibile vizibile pe ecran sau redate pe dispozitiv. Aici sunt incluse parole, informații de plată, fotografii, mesaje și conținut audio."</string>
-    <string name="screenrecord_audio_label" msgid="6183558856175159629">"Înregistrați conținut audio"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
+    <string name="screenrecord_audio_label" msgid="6183558856175159629">"Înregistrează audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Conținutul audio de la dispozitiv"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sunetul de la dispozitiv, precum muzică, apeluri și tonuri de sonerie"</string>
     <string name="screenrecord_mic_label" msgid="2111264835791332350">"Microfon"</string>
     <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Conținutul audio de la dispozitiv și microfon"</string>
-    <string name="screenrecord_start" msgid="330991441575775004">"Începeți"</string>
+    <string name="screenrecord_start" msgid="330991441575775004">"Începe"</string>
     <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Se înregistrează ecranul"</string>
     <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Se înregistrează ecranul și conținutul audio"</string>
     <string name="screenrecord_taps_label" msgid="1595690528298857649">"Afișează atingerile de pe ecran"</string>
@@ -133,10 +143,10 @@
     <string name="biometric_dialog_face_icon_description_authenticated" msgid="2242167416140740920">"Chip autentificat"</string>
     <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"Confirmat"</string>
     <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"Atinge Confirm pentru a finaliza"</string>
-    <string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"S-a deblocat cu ajutorul feței. Apasă pictograma de deblocare pentru a continua"</string>
+    <string name="biometric_dialog_tap_confirm_with_face" msgid="1092050545851021991">"Deblocat facial. Apasă pictograma Deblocare ca să continui."</string>
     <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"S-a deblocat cu ajutorul feței. Apasă pentru a continua."</string>
     <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"Chipul a fost recunoscut. Apasă pentru a continua."</string>
-    <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Chip recunoscut. Apăsați pictograma de deblocare să continuați."</string>
+    <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"Chip recunoscut. Apasă pictograma Deblocare ca să continui."</string>
     <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"Autentificat"</string>
     <string name="biometric_dialog_use_pin" msgid="8385294115283000709">"Folosește PIN-ul"</string>
     <string name="biometric_dialog_use_pattern" msgid="2315593393167211194">"Folosește modelul"</string>
@@ -146,16 +156,16 @@
     <string name="biometric_dialog_wrong_password" msgid="69477929306843790">"Parolă greșită"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="3083141271737748716">"Prea multe încercări incorecte.\nÎncearcă din nou peste <xliff:g id="NUMBER">%d</xliff:g> secunde."</string>
     <string name="biometric_dialog_credential_attempts_before_wipe" msgid="6751859711975516999">"Încearcă din nou. Încercarea <xliff:g id="ATTEMPTS_0">%1$d</xliff:g> din <xliff:g id="MAX_ATTEMPTS">%2$d</xliff:g>."</string>
-    <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Datele dvs. vor fi șterse"</string>
-    <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Dacă la următoarea încercare introduceți un model incorect, datele de pe acest dispozitiv vor fi șterse."</string>
-    <string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"Dacă la următoarea încercare introduceți un cod PIN incorect, datele de pe acest dispozitiv vor fi șterse."</string>
-    <string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"Dacă la următoarea încercare introduceți o parolă incorectă, datele de pe acest dispozitiv vor fi șterse."</string>
-    <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Dacă la următoarea încercare introduceți un model incorect, acest utilizator va fi șters."</string>
-    <string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Dacă la următoarea încercare introduceți un cod PIN incorect, acest utilizator va fi șters."</string>
-    <string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Dacă la următoarea încercare introduceți o parolă incorectă, acest utilizator va fi șters."</string>
-    <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Dacă la următoarea încercare introduceți un model incorect, profilul de serviciu și datele sale vor fi șterse."</string>
-    <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Dacă la următoarea încercare introduceți un cod PIN incorect, profilul de serviciu și datele sale vor fi șterse."</string>
-    <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Dacă la următoarea încercare introduceți o parolă incorectă, profilul de serviciu și datele sale vor fi șterse."</string>
+    <string name="biometric_dialog_last_attempt_before_wipe_dialog_title" msgid="2874250099278693477">"Datele tale vor fi șterse"</string>
+    <string name="biometric_dialog_last_pattern_attempt_before_wipe_device" msgid="6562299244825817598">"Dacă la următoarea încercare introduci un model incorect, datele de pe acest dispozitiv vor fi șterse."</string>
+    <string name="biometric_dialog_last_pin_attempt_before_wipe_device" msgid="9151756675698215723">"Dacă la următoarea încercare introduci un cod PIN incorect, datele de pe acest dispozitiv vor fi șterse."</string>
+    <string name="biometric_dialog_last_password_attempt_before_wipe_device" msgid="2363778585575998317">"Dacă la următoarea încercare introduci o parolă incorectă, datele de pe acest dispozitiv vor fi șterse."</string>
+    <string name="biometric_dialog_last_pattern_attempt_before_wipe_user" msgid="8400180746043407270">"Dacă la următoarea încercare introduci un model incorect, acest utilizator va fi șters."</string>
+    <string name="biometric_dialog_last_pin_attempt_before_wipe_user" msgid="4159878829962411168">"Dacă la următoarea încercare introduci un cod PIN incorect, acest utilizator va fi șters."</string>
+    <string name="biometric_dialog_last_password_attempt_before_wipe_user" msgid="4695682515465063885">"Dacă la următoarea încercare introduci o parolă incorectă, acest utilizator va fi șters."</string>
+    <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile" msgid="6045224069529284686">"Dacă la următoarea încercare introduci un model incorect, profilul de serviciu și datele sale vor fi șterse."</string>
+    <string name="biometric_dialog_last_pin_attempt_before_wipe_profile" msgid="545567685899091757">"Dacă la următoarea încercare introduci un cod PIN incorect, profilul de serviciu și datele sale vor fi șterse."</string>
+    <string name="biometric_dialog_last_password_attempt_before_wipe_profile" msgid="8538032972389729253">"Dacă la următoarea încercare introduci o parolă incorectă, profilul de serviciu și datele sale vor fi șterse."</string>
     <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"Atinge senzorul de amprente"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="4465698996175640549">"Pictograma amprentă"</string>
     <string name="fingerprint_dialog_use_fingerprint_instead" msgid="6178228876763024452">"Chipul nu a fost recunoscut. Folosește amprenta."</string>
@@ -280,21 +290,21 @@
     <string name="quick_settings_nfc_off" msgid="3465000058515424663">"Serviciul NFC este dezactivat"</string>
     <string name="quick_settings_nfc_on" msgid="1004976611203202230">"Serviciul NFC este activat"</string>
     <string name="quick_settings_screen_record_label" msgid="8650355346742003694">"Înregistrarea ecranului"</string>
-    <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Începeți"</string>
+    <string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Începe"</string>
     <string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Oprește"</string>
     <string name="quick_settings_onehanded_label" msgid="2416537930246274991">"Modul cu o mână"</string>
-    <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblocați microfonul dispozitivului?"</string>
-    <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblocați camera dispozitivului?"</string>
-    <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblocați camera și microfonul dispozitivului?"</string>
-    <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi microfonul."</string>
-    <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera."</string>
-    <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Astfel, deblocați accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera sau microfonul."</string>
+    <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Deblochezi microfonul dispozitivului?"</string>
+    <string name="sensor_privacy_start_use_camera_dialog_title" msgid="8807639852654305227">"Deblochezi camera dispozitivului?"</string>
+    <string name="sensor_privacy_start_use_mic_camera_dialog_title" msgid="4316471859905020023">"Deblochezi camera și microfonul dispozitivului?"</string>
+    <string name="sensor_privacy_start_use_mic_dialog_content" msgid="1624701280680913717">"Astfel, deblochezi accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi microfonul."</string>
+    <string name="sensor_privacy_start_use_camera_dialog_content" msgid="4704948062372435963">"Astfel, deblochezi accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera."</string>
+    <string name="sensor_privacy_start_use_mic_camera_dialog_content" msgid="3577642558418404919">"Astfel, deblochezi accesul pentru toate aplicațiile și serviciile care au permisiunea de a folosi camera sau microfonul."</string>
     <string name="sensor_privacy_start_use_mic_blocked_dialog_title" msgid="2640140287496469689">"Microfonul este blocat"</string>
     <string name="sensor_privacy_start_use_camera_blocked_dialog_title" msgid="7398084286822440384">"Camera este blocată"</string>
     <string name="sensor_privacy_start_use_mic_camera_blocked_dialog_title" msgid="195236134743281973">"Microfonul și camera sunt blocate"</string>
-    <string name="sensor_privacy_start_use_mic_blocked_dialog_content" msgid="2138318880682877747">"Pentru deblocare, deplasați comutatorul de confidențialitate de pe dispozitiv în poziția Microfon activat pentru a permite accesul la microfon. Consultați manualul dispozitivului ca să găsiți comutatorul de confidențialitate."</string>
-    <string name="sensor_privacy_start_use_camera_blocked_dialog_content" msgid="7216015168047965948">"Pentru deblocare, deplasați comutatorul de confidențialitate de pe dispozitiv în poziția Cameră foto activată pentru a permite accesul la cameră. Consultați manualul dispozitivului ca să găsiți comutatorul de confidențialitate."</string>
-    <string name="sensor_privacy_start_use_mic_camera_blocked_dialog_content" msgid="3960837827570483762">"Pentru deblocare, deplasați comutatorul de confidențialitate de pe dispozitiv în poziția Deblocat(ă) pentru a permite accesul. Consultați manualul dispozitivului ca să găsiți comutatorul de confidențialitate."</string>
+    <string name="sensor_privacy_start_use_mic_blocked_dialog_content" msgid="2138318880682877747">"Pentru deblocare, mută comutatorul de confidențialitate de pe dispozitiv în poziția Microfon activat pentru a permite accesul la microfon. Consultă manualul dispozitivului ca să găsești comutatorul de confidențialitate."</string>
+    <string name="sensor_privacy_start_use_camera_blocked_dialog_content" msgid="7216015168047965948">"Pentru deblocare, mută comutatorul de confidențialitate de pe dispozitiv în poziția Cameră foto activată pentru a permite accesul la cameră. Consultă manualul dispozitivului ca să găsești comutatorul de confidențialitate."</string>
+    <string name="sensor_privacy_start_use_mic_camera_blocked_dialog_content" msgid="3960837827570483762">"Pentru deblocare, mută comutatorul de confidențialitate de pe dispozitiv în poziția Deblocat(ă) pentru a permite accesul. Consultă manualul dispozitivului ca să găsești comutatorul de confidențialitate."</string>
     <string name="sensor_privacy_mic_unblocked_toast_content" msgid="306555320557065068">"Microfon disponibil"</string>
     <string name="sensor_privacy_camera_unblocked_toast_content" msgid="7843105715964332311">"Cameră foto disponibilă"</string>
     <string name="sensor_privacy_mic_camera_unblocked_toast_content" msgid="7339355093282661115">"Microfon și cameră disponibile"</string>
@@ -309,22 +319,22 @@
     <string name="tap_again" msgid="1315420114387908655">"Atinge din nou"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Glisează în sus pentru a deschide"</string>
     <string name="keyguard_unlock_press" msgid="9140109453735019209">"Apasă pictograma de deblocare pentru a deschide"</string>
-    <string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"S-a deblocat folosind fața. Glisați în sus și deschideți."</string>
-    <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"S-a deblocat cu ajutorul feței. Apasă pictograma de deblocare pentru a deschide"</string>
+    <string name="keyguard_face_successful_unlock_swipe" msgid="6180997591385846073">"Deblocat folosind chipul. Glisează în sus ca să deschizi."</string>
+    <string name="keyguard_face_successful_unlock_press" msgid="25520941264602588">"Deblocat facial. Apasă pictograma Deblocare ca să deschizi."</string>
     <string name="keyguard_face_successful_unlock_press_alt_1" msgid="5715461103913071474">"S-a deblocat cu ajutorul feței. Apasă pentru a deschide."</string>
     <string name="keyguard_face_successful_unlock_press_alt_2" msgid="8310787946357120406">"Chipul a fost recunoscut. Apasă pentru a deschide."</string>
-    <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Chip recunoscut. Apasă pictograma de deblocare pentru a deschide"</string>
+    <string name="keyguard_face_successful_unlock_press_alt_3" msgid="7219030481255573962">"Chip recunoscut. Apasă pictograma Deblocare ca să deschizi."</string>
     <string name="keyguard_face_successful_unlock" msgid="4203999851465708287">"S-a deblocat folosind fața"</string>
     <string name="keyguard_face_successful_unlock_alt1" msgid="5853906076353839628">"Chipul a fost recunoscut"</string>
   <string-array name="udfps_accessibility_touch_hints">
-    <item msgid="1901953991150295169">"Deplasați spre stânga"</item>
-    <item msgid="5558598599408514296">"Deplasați în jos"</item>
-    <item msgid="4844142668312841831">"Deplasați spre dreapta"</item>
-    <item msgid="5640521437931460125">"Deplasați în sus"</item>
+    <item msgid="1901953991150295169">"Mută la stânga"</item>
+    <item msgid="5558598599408514296">"Mută în jos"</item>
+    <item msgid="4844142668312841831">"Mută la dreapta"</item>
+    <item msgid="5640521437931460125">"Mută în sus"</item>
   </string-array>
     <string name="keyguard_retry" msgid="886802522584053523">"Glisează pentru a încerca din nou"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Deblochează pentru a folosi NFC"</string>
-    <string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației dvs."</string>
+    <string name="do_disclosure_generic" msgid="4896482821974707167">"Dispozitivul aparține organizației tale"</string>
     <string name="do_disclosure_with_name" msgid="2091641464065004091">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="do_financed_disclosure_with_name" msgid="6723004643314467864">"Acest dispozitiv este oferit de <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="phone_hint" msgid="6682125338461375925">"Glisează dinspre telefon"</string>
@@ -351,16 +361,30 @@
     <string name="guest_wipe_session_dontwipe" msgid="3211052048269304205">"Da, continuă"</string>
     <string name="guest_notification_app_name" msgid="2110425506754205509">"Modul pentru invitați"</string>
     <string name="guest_notification_session_active" msgid="5567273684713471450">"Folosește modul pentru invitați"</string>
-    <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Dacă adăugați un utilizator nou, veți ieși din modul pentru invitați și se vor șterge toate aplicațiile și datele din sesiunea pentru invitați actuală."</string>
+    <string name="user_add_user_message_guest_remove" msgid="5589286604543355007">\n\n"Dacă adaugi un utilizator nou, vei ieși din modul pentru invitați și se vor șterge toate aplicațiile și datele din sesiunea actuală pentru invitați."</string>
     <string name="user_limit_reached_title" msgid="2429229448830346057">"Ai atins limita de utilizatori"</string>
-    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Se poate crea doar un utilizator.}few{Puteți adăuga până la # utilizatori.}other{Puteți adăuga până la # de utilizatori.}}"</string>
-    <string name="user_remove_user_title" msgid="9124124694835811874">"Elimini utilizatorul?"</string>
+    <string name="user_limit_reached_message" msgid="1070703858915935796">"{count,plural, =1{Se poate crea doar un utilizator.}few{Poți adăuga până la # utilizatori.}other{Poți adăuga până la # de utilizatori.}}"</string>
+    <string name="user_remove_user_title" msgid="9124124694835811874">"Excluzi utilizatorul?"</string>
     <string name="user_remove_user_message" msgid="6702834122128031833">"Toate aplicațiile și datele acestui utilizator vor fi șterse."</string>
     <string name="user_remove_user_remove" msgid="8387386066949061256">"Elimină"</string>
-    <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va avea acces la toate informațiile vizibile pe ecran sau redate pe dispozitiv în timp ce înregistrați sau proiectați. Între aceste informații se numără parole, detalii de plată, fotografii, mesaje și conținutul audio pe care îl redați."</string>
-    <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Serviciul care oferă această funcție va avea acces la toate informațiile vizibile pe ecran sau redate pe dispozitiv în timp ce înregistrați sau proiectați. Între aceste informații se numără parole, detalii de plată, fotografii, mesaje și conținutul audio pe care îl redați."</string>
-    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Începeți să înregistrați sau să proiectați?"</string>
-    <string name="media_projection_dialog_title" msgid="3316063622495360646">"Începeți să înregistrați sau să proiectați cu <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> va avea acces la toate informațiile vizibile pe ecran sau redate pe dispozitiv în timp ce înregistrezi sau proiectezi. Între aceste informații se numără parole, detalii de plată, fotografii, mesaje și conținutul audio pe care îl redai."</string>
+    <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Serviciul care oferă această funcție va avea acces la toate informațiile vizibile pe ecran sau redate pe dispozitiv în timp ce înregistrezi sau proiectezi. Între aceste informații se numără parole, detalii de plată, fotografii, mesaje și conținutul audio pe care îl redai."</string>
+    <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Începi să înregistrezi sau să proiectezi?"</string>
+    <string name="media_projection_dialog_title" msgid="3316063622495360646">"Începi să înregistrezi sau să proiectezi cu <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Șterge toate notificările"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionează"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Istoric"</string>
@@ -373,22 +397,22 @@
     <string name="media_projection_action_text" msgid="3634906766918186440">"Începe acum"</string>
     <string name="empty_shade_text" msgid="8935967157319717412">"Nicio notificare"</string>
     <string name="quick_settings_disclosure_parental_controls" msgid="2114102871438223600">"Dispozitivul este gestionat de unul dintre părinți"</string>
-    <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organizația dvs. deține acest dispozitiv și poate monitoriza traficul de rețea"</string>
+    <string name="quick_settings_disclosure_management_monitoring" msgid="8231336875820702180">"Organizația ta deține acest dispozitiv și poate monitoriza traficul de rețea"</string>
     <string name="quick_settings_disclosure_named_management_monitoring" msgid="2831423806103479812">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> deține acest dispozitiv și poate monitoriza traficul din rețea"</string>
     <string name="quick_settings_financed_disclosure_named_management" msgid="2307703784594859524">"Acest dispozitiv este oferit de <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
-    <string name="quick_settings_disclosure_management_named_vpn" msgid="4137564460025113168">"Acest dispozitiv aparține organizației dvs. și este conectat la internet prin aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
+    <string name="quick_settings_disclosure_management_named_vpn" msgid="4137564460025113168">"Acest dispozitiv aparține organizației tale și e conectat la internet prin <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
     <string name="quick_settings_disclosure_named_management_named_vpn" msgid="2169227918166358741">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> și e conectat la internet prin <xliff:g id="VPN_APP">%2$s</xliff:g>."</string>
-    <string name="quick_settings_disclosure_management" msgid="5515296598440684962">"Dispozitivul aparține organizației dvs."</string>
+    <string name="quick_settings_disclosure_management" msgid="5515296598440684962">"Dispozitivul aparține organizației tale"</string>
     <string name="quick_settings_disclosure_named_management" msgid="3476472755775165827">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>"</string>
-    <string name="quick_settings_disclosure_management_vpns" msgid="929181757984262902">"Acest dispozitiv aparține organizației dvs. și este conectat la internet prin rețele VPN."</string>
+    <string name="quick_settings_disclosure_management_vpns" msgid="929181757984262902">"Acest dispozitiv aparține organizației tale și e conectat la internet prin VPN-uri."</string>
     <string name="quick_settings_disclosure_named_management_vpns" msgid="3312645578322079185">"Acest dispozitiv aparține organizației <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> și este conectat la internet prin rețele VPN."</string>
     <string name="quick_settings_disclosure_managed_profile_monitoring" msgid="1423899084754272514">"E posibil ca organizația ta să monitorizeze traficul de rețea în profilul de serviciu"</string>
     <string name="quick_settings_disclosure_named_managed_profile_monitoring" msgid="8321469176706219860">"E posibil ca <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> să monitorizeze traficul de rețea din profilul tău de serviciu"</string>
     <string name="quick_settings_disclosure_managed_profile_network_activity" msgid="2636594621387832827">"Adminul IT poate vedea profilul de serviciu"</string>
     <string name="quick_settings_disclosure_monitoring" msgid="8548019955631378680">"Este posibil ca rețeaua să fie monitorizată"</string>
     <string name="quick_settings_disclosure_vpns" msgid="3586175303518266301">"Acest dispozitiv este conectat la internet prin rețele VPN."</string>
-    <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="153393105176944100">"Aplicațiile dvs. pentru lucru sunt conectate la internet prin <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
-    <string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="451254750289172191">"Aplicațiile dvs. personale sunt conectate la internet prin aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
+    <string name="quick_settings_disclosure_managed_profile_named_vpn" msgid="153393105176944100">"Aplicațiile pentru lucru sunt conectate la internet prin <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
+    <string name="quick_settings_disclosure_personal_profile_named_vpn" msgid="451254750289172191">"Aplicațiile personale sunt conectate la internet prin <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
     <string name="quick_settings_disclosure_named_vpn" msgid="6191822916936028208">"Acest dispozitiv este conectat la internet prin aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>."</string>
     <string name="monitoring_title_financed_device" msgid="3659962357973919387">"Acest dispozitiv este oferit de <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
     <string name="monitoring_title_device_owned" msgid="7029691083837606324">"Gestionarea dispozitivului"</string>
@@ -397,18 +421,18 @@
     <string name="monitoring_subtitle_ca_certificate" msgid="8588092029755175800">"Certificate CA"</string>
     <string name="monitoring_button_view_policies" msgid="3869724835853502410">"Afișează politicile"</string>
     <string name="monitoring_button_view_controls" msgid="8316440345340701117">"Vezi opțiunile"</string>
-    <string name="monitoring_description_named_management" msgid="505833016545056036">"Dispozitivul aparține organizației <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdministratorul dvs. IT poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, datele asociate dispozitivului și informațiile despre locația dispozitivului.\n\nPentru mai multe informații, contactați administratorul IT."</string>
-    <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"Este posibil ca <xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> să acceseze date asociate dispozitivului, să gestioneze aplicații și să modifice setările acestuia.\n\nDacă aveți întrebări, luați legătura cu <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</string>
-    <string name="monitoring_description_management" msgid="4308879039175729014">"Dispozitivul aparține organizației dvs.\n\nAdministratorul dvs. IT poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, datele asociate dispozitivului și informațiile despre locația dispozitivului.\n\nPentru mai multe informații, contactați administratorul IT."</string>
+    <string name="monitoring_description_named_management" msgid="505833016545056036">"Dispozitivul aparține organizației <xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g>.\n\nAdministratorul IT poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, datele asociate dispozitivului și informațiile despre locația dispozitivului.\n\nPentru mai multe informații, contactează administratorul IT."</string>
+    <string name="monitoring_financed_description_named_management" msgid="6108439201399938668">"E posibil ca <xliff:g id="ORGANIZATION_NAME_0">%1$s</xliff:g> să acceseze date asociate dispozitivului, să gestioneze aplicații și să modifice setările acestuia.\n\nDacă ai întrebări, ia legătura cu <xliff:g id="ORGANIZATION_NAME_1">%2$s</xliff:g>."</string>
+    <string name="monitoring_description_management" msgid="4308879039175729014">"Dispozitivul aparține organizației tale.\n\nAdministratorul IT poate să monitorizeze și să gestioneze setările, accesul la nivelul companiei, aplicațiile, datele asociate dispozitivului și informațiile despre locația dispozitivului.\n\nPentru mai multe informații, contactează administratorul IT."</string>
     <string name="monitoring_description_management_ca_certificate" msgid="7785013130658110130">"Organizația ta a instalat un certificat CA pe acest dispozitiv. Traficul de rețea securizat poate fi monitorizat sau modificat."</string>
     <string name="monitoring_description_managed_profile_ca_certificate" msgid="7904323416598435647">"Organizația ta a instalat un certificat CA în profilul tău de serviciu. Traficul de rețea securizat poate fi monitorizat sau modificat."</string>
     <string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Pe acest dispozitiv este instalat un certificat CA. Traficul de rețea securizat poate fi monitorizat sau modificat."</string>
     <string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Administratorul tău a activat înregistrarea în jurnal pentru rețea, funcție care monitorizează traficul de pe dispozitivul tău."</string>
-    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratorul a activat înregistrarea în jurnal pentru rețea, funcție ce monitorizează traficul în profilul dvs. de serviciu, dar nu și în profilul personal."</string>
+    <string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Administratorul a activat înregistrarea în jurnal pentru rețea, funcție care monitorizează traficul în profilul de serviciu, dar nu și în profilul personal."</string>
     <string name="monitoring_description_named_vpn" msgid="7502657784155456414">"Acest dispozitiv este conectat la internet prin aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>. Activitatea în rețea, inclusiv e-mailurile și datele de navigare, sunt vizibile pentru administratorul IT."</string>
     <string name="monitoring_description_two_named_vpns" msgid="6726394451199620634">"Acest dispozitiv este conectat la internet prin aplicațiile <xliff:g id="VPN_APP_0">%1$s</xliff:g> și <xliff:g id="VPN_APP_1">%2$s</xliff:g>. Activitatea în rețea, inclusiv e-mailurile și datele de navigare, sunt vizibile pentru administratorul IT."</string>
-    <string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"Aplicațiile dvs. pentru lucru sunt conectate la internet prin aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>. Activitatea în rețea cu aplicațiile pentru lucru, inclusiv e-mailurile și datele de navigare, sunt vizibile pentru administratorul IT și pentru furnizorul de servicii VPN."</string>
-    <string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"Aplicațiile dvs. personale sunt conectate la internet prin aplicația <xliff:g id="VPN_APP">%1$s</xliff:g>. Activitatea în rețea, inclusiv e-mailurile și datele de navigare, sunt vizibile pentru furnizorul de servicii VPN."</string>
+    <string name="monitoring_description_managed_profile_named_vpn" msgid="7254359257263069766">"Aplicațiile pentru lucru sunt conectate la internet prin <xliff:g id="VPN_APP">%1$s</xliff:g>. Activitatea în rețea cu aplicațiile pentru lucru, inclusiv e-mailurile și datele de navigare, sunt vizibile pentru administratorul IT și pentru furnizorul de servicii VPN."</string>
+    <string name="monitoring_description_personal_profile_named_vpn" msgid="5083909710727365452">"Aplicațiile personale sunt conectate la internet prin <xliff:g id="VPN_APP">%1$s</xliff:g>. Activitatea în rețea, inclusiv e-mailurile și datele de navigare, sunt vizibile pentru furnizorul de servicii VPN."</string>
     <string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
     <string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Deschide Setări VPN"</string>
     <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Dispozitivul este gestionat de unul dintre părinți. Părintele poate să vadă și să gestioneze informații cum ar fi aplicațiile pe care le folosești, locația ta și durata de folosire a dispozitivului."</string>
@@ -426,14 +450,14 @@
     <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ă anulezi fixarea. Atinge 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ă anulezi fixarea. Atinge lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
-    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișată până anulați fixarea. Glisează în sus și ține apăsat pentru a anula fixarea."</string>
+    <string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișată până anulezi fixarea. Glisează în sus și ține apăsat pentru a anula fixarea."</string>
     <string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Astfel rămâne afișat până anulezi fixarea. Atinge lung opțiunea Recente pentru a anula fixarea."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Astfel rămâne afișat până anulezi fixarea. Atinge lung opțiunea Acasă pentru a anula fixarea."</string>
     <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Pot fi accesate date cu caracter personal (cum ar fi agenda și conținutul e-mailurilor)."</string>
     <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplicațiile fixate pot deschide alte aplicații."</string>
-    <string name="screen_pinning_toast" msgid="8177286912533744328">"Pentru a anula fixarea acestei aplicații, atingeți lung butoanele Înapoi și Recente"</string>
-    <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pentru a anula fixarea acestei aplicații, atingeți lung butoanele Înapoi și Acasă"</string>
-    <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pentru a anula fixarea acestei aplicații, glisați în sus și mențineți"</string>
+    <string name="screen_pinning_toast" msgid="8177286912533744328">"Pentru a anula fixarea acestei aplicații, atinge lung butoanele Înapoi și Recente"</string>
+    <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pentru a anula fixarea acestei aplicații, atinge lung butoanele Înapoi și Acasă"</string>
+    <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pentru a anula fixarea acestei aplicații, glisează în sus și menține"</string>
     <string name="screen_pinning_positive" msgid="3285785989665266984">"Am înțeles"</string>
     <string name="screen_pinning_negative" msgid="6882816864569211666">"Nu, mulțumesc"</string>
     <string name="screen_pinning_start" msgid="7483998671383371313">"Aplicație fixată"</string>
@@ -469,14 +493,14 @@
     <string name="status_bar_ethernet" msgid="5690979758988647484">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="87160847643623352">"Alarmă"</string>
     <string name="wallet_title" msgid="5369767670735827105">"Portofel"</string>
-    <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configurați pentru a face achiziții mai rapide și mai sigure cu telefonul dvs."</string>
+    <string name="wallet_empty_state_label" msgid="7776761245237530394">"Configurează pentru a face achiziții mai rapide și mai sigure cu telefonul"</string>
     <string name="wallet_app_button_label" msgid="7123784239111190992">"Afișează-le pe toate"</string>
     <string name="wallet_secondary_label_no_card" msgid="8488069304491125713">"Atinge pentru a deschide"</string>
     <string name="wallet_secondary_label_updating" msgid="5726130686114928551">"Se actualizează"</string>
     <string name="wallet_secondary_label_device_locked" msgid="5175862019125370506">"Deblochează pentru a folosi"</string>
     <string name="wallet_error_generic" msgid="257704570182963611">"A apărut o problemă la preluarea cardurilor. Încearcă din nou mai târziu"</string>
     <string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Setările ecranului de blocare"</string>
-    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scanați codul QR"</string>
+    <string name="qr_code_scanner_title" msgid="5290201053875420785">"Scanează codul QR"</string>
     <string name="status_bar_work" msgid="5238641949837091056">"Profil de serviciu"</string>
     <string name="status_bar_airplane" msgid="4848702508684541009">"Mod Avion"</string>
     <string name="zen_alarm_warning" msgid="7844303238486849503">"Nu vei auzi următoarea alarmă <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -507,7 +531,7 @@
     <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Fără sunet sau vibrații și apare în partea de jos a secțiunii de conversație"</string>
     <string name="notification_channel_summary_default" msgid="3282930979307248890">"Poate să sune sau să vibreze, în funcție de setările telefonului"</string>
     <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Poate să sune sau să vibreze, în funcție de setările telefonului. Conversațiile din balonul <xliff:g id="APP_NAME">%1$s</xliff:g> în mod prestabilit."</string>
-    <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Solicitați-i sistemului să stabilească dacă această notificare este sonoră sau cu vibrații."</string>
+    <string name="notification_channel_summary_automatic" msgid="5813109268050235275">"Solicită-i sistemului să stabilească dacă această notificare e sonoră sau cu vibrații."</string>
     <string name="notification_channel_summary_automatic_alerted" msgid="954166812246932240">"&lt;b&gt;Stare:&lt;/b&gt; promovată la prestabilită"</string>
     <string name="notification_channel_summary_automatic_silenced" msgid="7403004439649872047">"&lt;b&gt;Stare:&lt;/b&gt; setată ca Silențioasă"</string>
     <string name="notification_channel_summary_automatic_promoted" msgid="1301710305149590426">"&lt;b&gt;Stare:&lt;/b&gt; clasificată mai sus"</string>
@@ -641,8 +665,8 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Afișează pictogramele de notificare cu prioritate redusă"</string>
     <string name="other" msgid="429768510980739978">"Altele"</string>
-    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"eliminați cardul"</string>
-    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adăugați cardul la sfârșit"</string>
+    <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"elimină cardul"</string>
+    <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"adaugă cardul la sfârșit"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mută cardul"</string>
     <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Adaugă un card"</string>
     <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Mută pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
@@ -668,7 +692,7 @@
     <string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Telefonul se încălzise prea mult și s-a oprit pentru a se răci. Acum telefonul funcționează normal.\n\nTelefonul s-ar putea încălzi prea mult dacă:\n	• folosești aplicații care consumă multe resurse (de ex., jocuri, aplicații video/de navigare);\n	• descarci/încarci fișiere mari;\n	• folosești telefonul la temperaturi ridicate."</string>
     <string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Vezi pașii pentru îngrijire"</string>
     <string name="high_temp_title" msgid="2218333576838496100">"Telefonul se încălzește"</string>
-    <string name="high_temp_notif_message" msgid="1277346543068257549">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtinge pentru mai multe informații"</string>
+    <string name="high_temp_notif_message" msgid="1277346543068257549">"Anumite funcții sunt limitate în timp ce telefonul se răcește.\nAtinge pentru mai multe informații."</string>
     <string name="high_temp_dialog_message" msgid="3793606072661253968">"Telefonul va încerca automat să se răcească. Îl poți folosi în continuare, dar e 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">"Vezi pașii pentru îngrijire"</string>
     <string name="high_temp_alarm_title" msgid="8654754369605452169">"Deconectează dispozitivul"</string>
@@ -745,25 +769,25 @@
     <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Standby"</string>
     <string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string>
     <string name="magnification_controls_title" msgid="8421106606708891519">"Comenzi pentru fereastra de mărire"</string>
-    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Măriți"</string>
-    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Micșorați"</string>
-    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Deplasați în sus"</string>
-    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Deplasați în jos"</string>
-    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Deplasați spre stânga"</string>
-    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Deplasați spre dreapta"</string>
+    <string name="accessibility_control_zoom_in" msgid="1189272315480097417">"Mărește"</string>
+    <string name="accessibility_control_zoom_out" msgid="69578832020304084">"Micșorează"</string>
+    <string name="accessibility_control_move_up" msgid="6622825494014720136">"Mută în sus"</string>
+    <string name="accessibility_control_move_down" msgid="5390922476900974512">"Mută în jos"</string>
+    <string name="accessibility_control_move_left" msgid="8156206978511401995">"Mută la stânga"</string>
+    <string name="accessibility_control_move_right" msgid="8926821093629582888">"Mută spre dreapta"</string>
     <string name="magnification_mode_switch_description" msgid="2698364322069934733">"Comutator de mărire"</string>
-    <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Măriți tot ecranul"</string>
-    <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Măriți o parte a ecranului"</string>
+    <string name="magnification_mode_switch_state_full_screen" msgid="5229653514979530561">"Mărește tot ecranul"</string>
+    <string name="magnification_mode_switch_state_window" msgid="8597100249594076965">"Mărește o parte a ecranului"</string>
     <string name="magnification_mode_switch_click_label" msgid="2786203505805898199">"Comutator"</string>
-    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atingeți pentru a deschide funcțiile de accesibilitate. Personalizați sau înlocuiți butonul în Setări.\n\n"<annotation id="link">"Afișați setările"</annotation></string>
+    <string name="accessibility_floating_button_migration_tooltip" msgid="5217151214439341902">"Atinge ca să deschizi funcțiile de accesibilitate. Personalizează sau înlocuiește butonul în setări.\n\n"<annotation id="link">"Vezi setările"</annotation></string>
     <string name="accessibility_floating_button_docking_tooltip" msgid="6814897496767461517">"Mută butonul spre margine pentru a-l ascunde temporar"</string>
     <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Mută în stânga sus"</string>
     <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Mută în dreapta sus"</string>
     <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Mută în stânga jos"</string>
     <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Mută în dreapta jos"</string>
-    <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mutați în afară și ascundeți"</string>
-    <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mutați în afară și afișați"</string>
-    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activați / dezactivați"</string>
+    <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Mută la margine și ascunde"</string>
+    <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Mută de la margine și afișează"</string>
+    <string name="accessibility_floating_button_action_double_tap_to_toggle" msgid="7976492639670692037">"Activează / dezactivează"</string>
     <string name="quick_controls_title" msgid="6839108006171302273">"Comenzile dispozitivelor"</string>
     <string name="controls_providers_title" msgid="6879775889857085056">"Alege aplicația pentru a adăuga comenzi"</string>
     <string name="controls_number_of_favorites" msgid="4481806788981836355">"{count,plural, =1{S-a adăugat # comandă.}few{S-au adăugat # comenzi.}other{S-au adăugat # de comenzi.}}"</string>
@@ -771,30 +795,30 @@
     <string name="accessibility_control_favorite" msgid="8694362691985545985">"Marcată ca preferată"</string>
     <string name="accessibility_control_favorite_position" msgid="54220258048929221">"Marcată ca preferată, poziția <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="accessibility_control_not_favorite" msgid="1291760269563092359">"S-a anulat marcarea ca preferată"</string>
-    <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"marcați ca preferată"</string>
-    <string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"anulați marcarea ca preferată"</string>
+    <string name="accessibility_control_change_favorite" msgid="2943178027582253261">"marchează ca preferată"</string>
+    <string name="accessibility_control_change_unfavorite" msgid="6997408061750740327">"anulează marcarea ca preferată"</string>
     <string name="accessibility_control_move" msgid="8980344493796647792">"Mută pe poziția <xliff:g id="NUMBER">%d</xliff:g>"</string>
     <string name="controls_favorite_default_title" msgid="967742178688938137">"Comenzi"</string>
     <string name="controls_favorite_subtitle" msgid="6481675111056961083">"Alege comenzile de accesat din Setările rapide"</string>
-    <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Țineți apăsat și trageți pentru a rearanja comenzile"</string>
+    <string name="controls_favorite_rearrange" msgid="5616952398043063519">"Ține apăsat și trage pentru a rearanja comenzile"</string>
     <string name="controls_favorite_removed" msgid="5276978408529217272">"Au fost șterse toate comenzile"</string>
     <string name="controls_favorite_toast_no_changes" msgid="7094494210840877931">"Modificările nu au fost salvate"</string>
     <string name="controls_favorite_see_other_apps" msgid="7709087332255283460">"Vezi alte aplicații"</string>
-    <string name="controls_favorite_load_error" msgid="5126216176144877419">"Comenzile nu au putut fi încărcate. Accesați aplicația <xliff:g id="APP">%s</xliff:g> pentru a vă asigura că setările aplicației nu s-au schimbat."</string>
+    <string name="controls_favorite_load_error" msgid="5126216176144877419">"Comenzile nu au putut fi încărcate. Accesează aplicația <xliff:g id="APP">%s</xliff:g> pentru a te asigura că setările aplicației nu s-au schimbat."</string>
     <string name="controls_favorite_load_none" msgid="7687593026725357775">"Nu sunt disponibile comenzi compatibile"</string>
     <string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Altul"</string>
     <string name="controls_dialog_title" msgid="2343565267424406202">"Adaugă la comenzile dispozitivelor"</string>
     <string name="controls_dialog_ok" msgid="2770230012857881822">"Adaugă"</string>
     <string name="controls_dialog_message" msgid="342066938390663844">"Sugerat de <xliff:g id="APP">%s</xliff:g>"</string>
     <string name="controls_tile_locked" msgid="731547768182831938">"Dispozitiv blocat"</string>
-    <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Vedeți și controlați dispozitivele de pe ecranul de blocare?"</string>
-    <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Puteți adăuga comenzi pentru dispozitivele externe pe ecranul de blocare.\n\nAplicația de pe dispozitiv vă poate da posibilitatea să controlați unele dispozitive fără să deblocați telefonul.\n\nPuteți face modificări oricând în Setări."</string>
-    <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Controlați dispozitivele de pe ecranul de blocare?"</string>
-    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Puteți să controlați unele dispozitive fără să deblocați telefonul sau tableta.\n\nAplicația de pe dispozitiv stabilește dispozitivele care pot fi controlate astfel."</string>
+    <string name="controls_settings_show_controls_dialog_title" msgid="3357852503553809554">"Afișezi și controlezi dispozitivele de pe ecranul de blocare?"</string>
+    <string name="controls_settings_show_controls_dialog_message" msgid="7666211700524587969">"Poți adăuga comenzi pentru dispozitivele externe pe ecranul de blocare.\n\nAplicația de pe dispozitiv îți poate permite să controlezi unele dispozitive fără să deblochezi telefonul.\n\nPoți face modificări oricând în setări."</string>
+    <string name="controls_settings_trivial_controls_dialog_title" msgid="7593188157655036677">"Controlezi dispozitivele de pe ecranul de blocare?"</string>
+    <string name="controls_settings_trivial_controls_dialog_message" msgid="237183787721917586">"Poți controla unele dispozitive fără să deblochezi telefonul sau tableta.\n\nAplicația de pe dispozitiv stabilește dispozitivele care pot fi controlate astfel."</string>
     <string name="controls_settings_dialog_neutral_button" msgid="4514446354793124140">"Nu, mulțumesc"</string>
     <string name="controls_settings_dialog_positive_button" msgid="436070672551674863">"Da"</string>
     <string name="controls_pin_use_alphanumeric" msgid="8478371861023048414">"Codul PIN conține litere sau simboluri"</string>
-    <string name="controls_pin_verify" msgid="3452778292918877662">"Verificați <xliff:g id="DEVICE">%s</xliff:g>"</string>
+    <string name="controls_pin_verify" msgid="3452778292918877662">"Verifică <xliff:g id="DEVICE">%s</xliff:g>"</string>
     <string name="controls_pin_wrong" msgid="6162694056042164211">"Cod PIN greșit"</string>
     <string name="controls_pin_instructions" msgid="6363309783822475238">"Introdu codul PIN"</string>
     <string name="controls_pin_instructions_retry" msgid="1566667581012131046">"Încearcă alt cod PIN"</string>
@@ -802,7 +826,7 @@
     <string name="controls_structure_tooltip" msgid="4355922222944447867">"Glisează pentru a vedea mai multe"</string>
     <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string>
     <string name="controls_media_title" msgid="1746947284862928133">"Media"</string>
-    <string name="controls_media_close_session" msgid="4780485355795635052">"Ascundeți comanda media pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="controls_media_close_session" msgid="4780485355795635052">"Ascunzi comanda media pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
     <string name="controls_media_active_session" msgid="3146882316024153337">"Sesiunea media actuală nu se poate ascunde."</string>
     <string name="controls_media_dismiss_button" msgid="4485675693008031646">"Ascunde"</string>
     <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string>
@@ -819,17 +843,17 @@
     <string name="controls_media_smartspace_rec_item_description" msgid="2189271793070870883">"Redă <xliff:g id="SONG_NAME">%1$s</xliff:g> de la <xliff:g id="ARTIST_NAME">%2$s</xliff:g> în <xliff:g id="APP_LABEL">%3$s</xliff:g>"</string>
     <string name="controls_media_smartspace_rec_item_no_artist_description" msgid="8703614798636591077">"Redă <xliff:g id="SONG_NAME">%1$s</xliff:g> în <xliff:g id="APP_LABEL">%2$s</xliff:g>"</string>
     <string name="media_transfer_undo" msgid="1895606387620728736">"Anulează"</string>
-    <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Apropiați-vă pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
-    <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Mergeți mai aproape de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redați acolo"</string>
+    <string name="media_move_closer_to_start_cast" msgid="2673104707465013176">"Apropie-te pentru a reda pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
+    <string name="media_move_closer_to_end_cast" msgid="6495907340926563656">"Apropie-te de <xliff:g id="DEVICENAME">%1$s</xliff:g> ca să redai acolo"</string>
     <string name="media_transfer_playing_different_device" msgid="7186806382609785610">"Se redă pe <xliff:g id="DEVICENAME">%1$s</xliff:g>"</string>
     <string name="media_transfer_failed" msgid="7955354964610603723">"A apărut o eroare. Încearcă din nou."</string>
-    <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string>
+    <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verifică aplicația"</string>
     <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string>
     <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string>
-    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nu s-a putut accesa <xliff:g id="DEVICE">%1$s</xliff:g>. Accesați aplicația <xliff:g id="APPLICATION">%2$s</xliff:g> pentru a vă asigura de disponibilitatea comenzii și că setările aplicației nu s-au schimbat."</string>
+    <string name="controls_error_removed_message" msgid="2885911717034750542">"Nu s-a putut accesa <xliff:g id="DEVICE">%1$s</xliff:g>. Accesează aplicația <xliff:g id="APPLICATION">%2$s</xliff:g> pentru a te asigura de disponibilitatea comenzii și că setările aplicației nu s-au schimbat."</string>
     <string name="controls_open_app" msgid="483650971094300141">"Deschide aplicația"</string>
     <string name="controls_error_generic" msgid="352500456918362905">"Starea nu se poate încărca"</string>
-    <string name="controls_error_failed" msgid="960228639198558525">"Eroare, încercați din nou"</string>
+    <string name="controls_error_failed" msgid="960228639198558525">"Eroare, încearcă din nou"</string>
     <string name="controls_menu_add" msgid="4447246119229920050">"Adaugă comenzi"</string>
     <string name="controls_menu_edit" msgid="890623986951347062">"Editează comenzile"</string>
     <string name="media_output_dialog_add_output" msgid="5642703238877329518">"Adaugă ieșiri"</string>
@@ -839,15 +863,15 @@
     <string name="media_output_dialog_disconnected" msgid="7090512852817111185">"(deconectat)"</string>
     <string name="media_output_dialog_connect_failed" msgid="3080972621975339387">"Nu se poate comuta. Atinge pentru a încerca din nou."</string>
     <string name="media_output_dialog_pairing_new" msgid="5098212763195577270">"Conectează un dispozitiv"</string>
-    <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pentru a proiecta această sesiune, deschideți aplicația."</string>
+    <string name="media_output_dialog_launch_app_text" msgid="1527413319632586259">"Pentru a proiecta această sesiune, deschide aplicația."</string>
     <string name="media_output_dialog_unknown_launch_app_name" msgid="1084899329829371336">"Aplicație necunoscută"</string>
-    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Nu mai proiectați"</string>
+    <string name="media_output_dialog_button_stop_casting" msgid="6581379537930199189">"Nu mai proiecta"</string>
     <string name="media_output_dialog_accessibility_title" msgid="4681741064190167888">"Dispozitive disponibile pentru ieșire audio."</string>
     <string name="media_output_dialog_accessibility_seekbar" msgid="5332843993805568978">"Volum"</string>
     <string name="media_output_first_broadcast_title" msgid="6292237789860753022">"Cum funcționează transmisia"</string>
-    <string name="media_output_broadcast" msgid="3555580945878071543">"Transmiteți"</string>
-    <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Persoanele din apropiere cu dispozitive Bluetooth compatibile pot asculta conținutul pe care îl transmiteți"</string>
-    <string name="media_output_broadcasting_message" msgid="4150299923404886073">"Ca să asculte transmisia dvs., persoanele din apropiere cu dispozitive Bluetooth compatibile vă pot scana codul QR sau pot folosi numele și parola transmisiei."</string>
+    <string name="media_output_broadcast" msgid="3555580945878071543">"Transmite"</string>
+    <string name="media_output_first_notify_broadcast_message" msgid="6353857724136398494">"Persoanele din apropiere cu dispozitive Bluetooth compatibile pot asculta conținutul pe care îl transmiți"</string>
+    <string name="media_output_broadcasting_message" msgid="4150299923404886073">"Ca să-ți asculte transmisia, persoanele din apropiere cu dispozitive Bluetooth compatibile pot să îți scaneze codul QR sau să folosească numele și parola transmisiei."</string>
     <string name="media_output_broadcast_name" msgid="8786127091542624618">"Numele transmisiei"</string>
     <string name="media_output_broadcast_code" msgid="870795639644728542">"Parolă"</string>
     <string name="media_output_broadcast_dialog_save" msgid="7910865591430010198">"Salvează"</string>
@@ -859,8 +883,8 @@
     <string name="build_number_copy_toast" msgid="877720921605503046">"Numărul versiunii s-a copiat în clipboard."</string>
     <string name="basic_status" msgid="2315371112182658176">"Deschide conversația"</string>
     <string name="select_conversation_title" msgid="6716364118095089519">"Widgeturi pentru conversație"</string>
-    <string name="select_conversation_text" msgid="3376048251434956013">"Atingeți o conversație ca să o adăugați pe ecranul de pornire"</string>
-    <string name="no_conversations_text" msgid="5354115541282395015">"Conversațiile dvs. recente se vor afișa aici"</string>
+    <string name="select_conversation_text" msgid="3376048251434956013">"Atinge o conversație ca să o adaugi pe ecranul de pornire"</string>
+    <string name="no_conversations_text" msgid="5354115541282395015">"Conversațiile recente se vor afișa aici"</string>
     <string name="priority_conversations" msgid="3967482288896653039">"Conversații cu prioritate"</string>
     <string name="recent_conversations" msgid="8531874684782574622">"Conversații recente"</string>
     <string name="days_timestamp" msgid="5821854736213214331">"Acum <xliff:g id="DURATION">%1$s</xliff:g> zile"</string>
@@ -897,10 +921,10 @@
     <string name="battery_state_unknown_notification_text" msgid="13720937839460899">"Atinge pentru mai multe informații"</string>
     <string name="qs_alarm_tile_no_alarm" msgid="4826472008616807923">"Nicio alarmă setată"</string>
     <string name="accessibility_fingerprint_label" msgid="5255731221854153660">"Senzor de amprentă"</string>
-    <string name="accessibility_authenticate_hint" msgid="798914151813205721">"Autentificați-vă"</string>
+    <string name="accessibility_authenticate_hint" msgid="798914151813205721">"autentifică-te"</string>
     <string name="accessibility_enter_hint" msgid="2617864063504824834">"Accesează dispozitivul"</string>
-    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosiți amprenta ca să deschideți"</string>
-    <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atingeți senzorul de amprentă pentru a vă autentifica."</string>
+    <string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosește amprenta ca să deschizi"</string>
+    <string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atinge senzorul de amprentă pentru a te autentifica."</string>
     <string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Apel telefonic în desfășurare"</string>
     <string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string>
     <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
@@ -910,23 +934,23 @@
     <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nu sunt disponibile alte rețele"</string>
     <string name="all_network_unavailable" msgid="4112774339909373349">"Nicio rețea disponibilă"</string>
     <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
-    <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Atingeți o rețea pentru a vă conecta"</string>
+    <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Atinge o rețea pentru a te conecta"</string>
     <string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblochează pentru a vedea rețelele"</string>
     <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string>
     <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string>
     <string name="wifi_wont_autoconnect_for_now" msgid="5782282612749867762">"Deocamdată, Wi-Fi nu se poate conecta automat"</string>
     <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
-    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectați ethernet"</string>
-    <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pentru a îmbunătăți experiența cu dispozitivul, aplicațiile și serviciile pot să caute în continuare rețele Wi‑Fi chiar și atunci când conexiunea Wi-Fi este dezactivată. Puteți să schimbați acest aspect din setările pentru căutarea de rețele Wi-Fi. "<annotation id="link">"Schimbați"</annotation></string>
+    <string name="to_switch_networks_disconnect_ethernet" msgid="6698111101156951955">"Pentru a schimba rețeaua, deconectează ethernet"</string>
+    <string name="wifi_scan_notify_message" msgid="3753839537448621794">"Pentru a îmbunătăți experiența cu dispozitivul, aplicațiile și serviciile pot să caute în continuare rețele Wi‑Fi chiar și atunci când conexiunea Wi-Fi e dezactivată. Poți schimba opțiunea din setările pentru căutarea de rețele Wi-Fi. "<annotation id="link">"Schimbă"</annotation></string>
     <string name="turn_off_airplane_mode" msgid="8425587763226548579">"Dezactivează modul Avion"</string>
     <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> vrea să adauge următorul card la Setări rapide"</string>
-    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adaugă un card"</string>
-    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nu adăugați un card"</string>
+    <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Adaugă cardul"</string>
+    <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Nu adăuga cardul"</string>
     <string name="qs_user_switch_dialog_title" msgid="3045189293587781366">"Alege utilizatorul"</string>
     <string name="fgs_manager_footer_label" msgid="8276763570622288231">"{count,plural, =1{# aplicație este activă}few{# aplicații sunt active}other{# de aplicații sunt active}}"</string>
     <string name="fgs_dot_content_description" msgid="2865071539464777240">"Informații noi"</string>
     <string name="fgs_manager_dialog_title" msgid="5879184257257718677">"Aplicații active"</string>
-    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Aceste aplicații sunt active și rulează, chiar dacă nu le folosiți. Astfel, funcțiile lor sunt îmbunătățite, dar autonomia bateriei poate fi afectată."</string>
+    <string name="fgs_manager_dialog_message" msgid="2670045017200730076">"Aceste aplicații sunt active și rulează, chiar dacă nu le folosești. Astfel, funcțiile lor sunt îmbunătățite, dar autonomia bateriei poate fi afectată."</string>
     <string name="fgs_manager_app_item_stop_button_label" msgid="7188317969020801156">"Oprește"</string>
     <string name="fgs_manager_app_item_stop_button_stopped_label" msgid="6950382004441263922">"Oprită"</string>
     <string name="clipboard_edit_text_done" msgid="4551887727694022409">"Gata"</string>
@@ -943,7 +967,7 @@
     <string name="clipboard_editor" msgid="2971197550401892843">"Editor de clipboard"</string>
     <string name="clipboard_overlay_window_name" msgid="6450043652167357664">"Clipboard"</string>
     <string name="clipboard_image_preview" msgid="2156475174343538128">"Previzualizarea imaginii"</string>
-    <string name="clipboard_edit" msgid="4500155216174011640">"editați"</string>
+    <string name="clipboard_edit" msgid="4500155216174011640">"editează"</string>
     <string name="add" msgid="81036585205287996">"Adaugă"</string>
     <string name="manage_users" msgid="1823875311934643849">"Gestionează utilizatorii"</string>
     <string name="drag_split_not_supported" msgid="4326847447699729722">"Notificarea nu acceptă tragerea pe ecranul împărțit."</string>
@@ -956,9 +980,9 @@
     <string name="dream_overlay_status_bar_notification_indicator" msgid="8091389255691081711">"{count,plural, =1{# notificare}few{# notificări}other{# de notificări}}"</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">"Se difuzează"</string>
-    <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Opriți difuzarea <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
-    <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Dacă difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbați rezultatul, difuzarea actuală se va opri"</string>
-    <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Difuzați <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
+    <string name="bt_le_audio_broadcast_dialog_title" msgid="3605428497924077811">"Oprești transmisia <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="7889684551194225793">"Dacă transmiți <xliff:g id="SWITCHAPP">%1$s</xliff:g> sau schimbi ieșirea, transmisia actuală se va opri"</string>
+    <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="6098768269397105733">"Transmite <xliff:g id="SWITCHAPP">%1$s</xliff:g>"</string>
     <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Schimbă rezultatul"</string>
     <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Necunoscută"</string>
     <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EE, z LLL"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 5d804b9..84b5061 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Текущее уведомление для записи видео с экрана"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Начать запись?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"В записи может появиться конфиденциальная информация, которая видна на экране или воспроизводится на устройстве, например пароли, сведения о платежах, фотографии, сообщения и аудиозаписи."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Записывать аудио"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Звук с устройства"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук с вашего устройства, например музыка, звонки и рингтоны"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Во время записи или трансляции у сервиса, предоставляющего эту функцию, будет доступ ко всей информации, которая видна на экране или воспроизводится на устройстве, включая пароли, сведения о платежах, фотографии, сообщения и звуки."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Начать запись или трансляцию?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Начать запись или трансляцию через приложение \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\"?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистить все"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Настроить"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 17a6a19..1ccdbf3 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"තිර පටිගත කිරීමේ සැසියක් සඳහා කෙරෙන දැනුම් දීම"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"පටිගත කිරීම ආරම්භ කරන්නද?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"පටිගත කරන අතරතුර, Android පද්ධතියට ඔබේ තිරයේ පෙනෙන හෝ ඔබේ උපාංගයේ වාදනය කරන ඕනෑම සංවේදී තොරතුරක් ග්‍රහණය කර ගැනීමට හැකිය. මෙයට මුරපද, ගෙවීම් තොරතුරු, ඡායාරූප, පණිවිඩ සහ ඕඩියෝ ඇතුළත් වේ."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ඕඩියෝ පටිගත කරන්න"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"උපාංග ඕඩියෝ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"සංගීතය, ඇමතුම් සහ නාද රිද්ම වැනි ඔබේ උපාංගය වෙතින් ශබ්ද"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"මෙම ශ්‍රිතය සපයන සේවාවට පටිගත කරන හෝ විකාශ කරන අතරතුර ඔබේ තිරයේ දිස් වන හෝ ඔබේ උපාංගයෙන් වාදනය කරන සියලු තොරතුරු වෙත ප්‍රවේශය ලැබෙනු ඇත. මෙහි මුරපද, ගෙවීම් විස්තර, ඡායාරූප, පණිවිඩ සහ ඔබ වාදනය කරන ඕඩියෝ යනාදි තොරතුරු ඇතුළත් වේ."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"පටිගත කිරීම හෝ විකාශය කිරීම ආරම්භ කරන්නද?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> සමග පටිගත කිරීම හෝ විකාශය කිරීම ආරම්භ කරන්නද?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"සියල්ල හිස් කරන්න"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"කළමනාකරණය කරන්න"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ඉතිහාසය"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ce51293..0818e07 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Zobrazuje sa upozornenie týkajúce sa relácie záznamu obrazovky"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Chcete spustiť nahrávanie?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Počas nahrávania zaznamená systém Android všetky citlivé údaje, ktoré sa zobrazia na obrazovke alebo prehrajú v zariadení. Zahrnuje to heslá, platobné údaje, fotky, správy a zvuky."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Nahrávať celú obrazovku"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Nahrávať jednu aplikáciu"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Počas nahrávania bude mať Android prístup k všetkému na obrazovke, prípadne k obsahu, ktorý sa bude v zariadení prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Počas nahrávania aplikácie bude mať Android prístup k všetkému obsahu, ktorý sa v nej bude zobrazovať alebo prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Spustiť nahrávanie"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Nahrávať zvuk"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk zariadenia"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk zo zariadenia, napríklad hudba, hovory a tóny zvonenia"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Služba poskytujúca túto funkciu bude mať prístup k všetkým informáciám zobrazovaným na obrazovke alebo prehrávaným v zariadení počas nahrávania či prenosu. Patria medzi ne informácie, akými sú napríklad heslá, platobné podrobnosti, fotky, správy a prehrávaný zvuk."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Chcete začať nahrávanie alebo prenos?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Chcete spustiť nahrávanie alebo prenos s aktivovaným povolením <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Chcete povoliť aplikácii <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> zdieľanie alebo nahrávanie?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Celá obrazovka"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Jedna aplikácia"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Počas zdieľania, nahrávania alebo prenosu bude mať <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému na obrazovke, prípadne k obsahu, ktorý sa bude v zariadení prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Počas zdieľania, nahrávania alebo prenosu bude mať aplikácia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> prístup k všetkému obsahu, ktorý sa v nej bude zobrazovať alebo prehrávať. Preto venujte zvýšenú pozornosť heslám, platobným údajom, správam a ďalším citlivým údajom."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Pokračovať"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Aplikácia na zdieľanie alebo nahrávanie"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Vymazať všetko"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovať"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"História"</string>
@@ -623,7 +635,7 @@
     <string name="right_keycode" msgid="2480715509844798438">"Pravý kód klávesnice"</string>
     <string name="left_icon" msgid="5036278531966897006">"Ľavá ikona"</string>
     <string name="right_icon" msgid="1103955040645237425">"Pravá ikona"</string>
-    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Pridržaním a presunutím pridáte dlaždice"</string>
+    <string name="drag_to_add_tiles" msgid="8933270127508303672">"Pridržaním a presunutím pridáte karty"</string>
     <string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Dlaždice môžete usporiadať pridržaním a presunutím"</string>
     <string name="drag_to_remove_tiles" msgid="4682194717573850385">"Presunutím sem odstránite"</string>
     <string name="drag_to_remove_disabled" msgid="933046987838658850">"Minimálny počet vyžadovaných dlaždíc: <xliff:g id="MIN_NUM_TILES">%1$d</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 620d9b5..b31033f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Nenehno obveščanje o seji snemanja zaslona"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Želite začeti snemati?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Med snemanjem lahko sistem Android zajame morebitne občutljive podatke, ki so prikazani na zaslonu ali se predvajajo v napravi. To vključuje gesla, podatke za plačilo, fotografije, sporočila in zvok."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Snemanje celotnega zaslona"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Snemanje posamezne aplikacije"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Med snemanjem ima Android dostop do vsega, kar je prikazano na zaslonu ali se predvaja v napravi. Zato bodite previdni z gesli, podatki za plačilo, sporočili ali drugimi občutljivimi podatki."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Med snemanjem aplikacije ima Android dostop do vsega, kar je prikazano ali predvajano v tej aplikaciji, zato bodite previdni z gesli, podatki za plačilo, sporočili ali drugimi občutljivimi podatki."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Začni snemanje"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Snemanje zvoka"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvok v napravi"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvoki v napravi, kot so glasba, klici in toni zvonjenja."</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Storitev, ki zagotavlja to funkcijo, bo imela dostop do vseh podatkov, ki so med snemanjem ali predvajanjem prikazani na vašem zaslonu ali se predvajajo iz vaše naprave. To vključuje podatke, kot so gesla, podrobnosti o plačilu, fotografije, sporočila in zvok, ki ga predvajate."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Želite začeti snemati ali predvajati?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Želite začeti snemati ali predvajati z aplikacijo <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Ali aplikaciji <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dovolite deljenje ali snemanje?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Celoten zaslon"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Posamezna aplikacija"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Pri deljenju, snemanju ali predvajanju ima aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dostop do vsega, kar je prikazano na zaslonu ali se predvaja v napravi. Zato bodite previdni z gesli, podatki za plačilo, sporočili ali drugimi občutljivimi podatki."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Pri deljenju, snemanju ali predvajanju aplikacije ima aplikacija <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> dostop do vsega, kar je prikazano ali predvajano v tej aplikaciji, zato bodite previdni z gesli, podatki za plačilo, sporočili ali drugimi občutljivimi podatki."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Naprej"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Deljenje ali snemanje aplikacije"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Izbriši vse"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljaj"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Zgodovina"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index be38908..dcebddb 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Njoftim i vazhdueshëm për një seancë regjistrimi të ekranit"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Të niset regjistrimi?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Gjatë regjistrimit, sistemi Android mund të regjistrojë çdo informacion delikat që është i dukshëm në ekranin tënd ose që luhet në pajisje. Kjo përfshin fjalëkalimet, informacionin e pagesave, fotografitë, mesazhet dhe audion."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Regjistro audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audioja e pajisjes"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Tingulli nga pajisja, si muzika, telefonatat dhe tonet e ziles"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Shërbimi që e ofron këtë funksion do të ketë qasje te të gjitha informacionet që janë të dukshme në ekran ose që luhen nga pajisja jote gjatë regjistrimit ose transmetimit. Kjo përfshin informacione, si p.sh.: fjalëkalimet, detajet e pagesave, fotografitë, mesazhet dhe audion që luan ti."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Do të fillosh regjistrimin ose transmetimin?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Fillo regjistrimin ose transmetimin me <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Pastroji të gjitha"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Menaxho"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historiku"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index f7ef654..e380b0e 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Обавештење о сесији снимања екрана је активно"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Желите да започнете снимање?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Током снимања Android систем може да сними осетљиве информације које су видљиве на екрану или које се пуштају на уређају. То обухвата лозинке, информације о плаћању, слике, поруке и звук."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Снимај цео екран"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Снимај једну апликацију"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Android има приступ комплетном садржају који је видљив на екрану или се пушта на уређају док снимате. Будите пажљиви са лозинкама, информацијама о плаћању, порукама или другим осетљивим информацијама."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Када снимате апликацију, Android има приступ комплетном садржају који је видљив или се пушта у тој апликацији. Будите пажљиви са лозинкама, информацијама о плаћању, порукама или другим осетљивим информацијама."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Започни снимање"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Снимај звук"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Звук уређаја"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук са уређаја, на пример, музика, позиви и мелодије звона"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Услуга која пружа ову функцију ће имати приступ свим информацијама које се приказују на екрану или репродукују са уређаја током снимања или пребацивања. То обухвата информације попут лозинки, информација о плаћању, слика, порука и звука који пуштате."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Желите да почнете снимање или пребацивање?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Желите да почнете снимање или пребацивање помоћу апликације <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Желите да дозволите дељење и снимање за <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Цео екран"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Једна апликација"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Када делите, снимате или пребацујете, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има приступ комплетном садржају који је видљив на екрану или се пушта на уређају. Будите пажљиви са лозинкама, информацијама о плаћању, порукама или другим осетљивим информацијама."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Када делите, снимате или пребацујете апликацију, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> има приступ комплетном садржају који је видљив или се пушта у тој апликацији. Будите пажљиви са лозинкама, информацијама о плаћању, порукама или другим осетљивим информацијама."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Настави"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Делите или снимите апликацију"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Обриши све"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Управљајте"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d3bd2cd..77f0d30 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Avisering om att skärminspelning pågår"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Vill du starta inspelningen?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"När du spelar in kan Android-systemet registrera alla känsliga uppgifter som visas på skärmen eller spelas upp på enheten. Detta omfattar lösenord, betalningsuppgifter, foton, meddelanden och ljud."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Spela in ljud"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Ljud på enheten"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Ljud från enheten, till exempel musik, samtal och ringsignaler"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Den tjänst som tillhandahåller funktionen får åtkomst till all information som visas på skärmen eller spelas upp från enheten när du spelar in eller castar. Detta omfattar uppgifter som lösenord, betalningsinformation, foton, meddelanden och ljud som du spelar upp."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vill du börja spela in eller casta?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Vill du börja spela in eller casta med <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Rensa alla"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Hantera"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index e29fbd2..3ba8d30 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Arifa inayoendelea ya kipindi cha kurekodi skrini"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Ungependa kuanza kurekodi?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Wakati wa kurekodi, Mfumo wa Android unaweza kunasa maelezo yoyote nyeti yanayoonekana kwenye skrini au yanayochezwa kwenye kifaa chako. Hii ni pamoja na manenosiri, maelezo ya malipo, picha, ujumbe na sauti."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Rekodi skrini nzima"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Rekodi programu moja"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Unaporekodi, Android inaweza kufikia kitu chochote kitakachoonekana kwenye skrini yako au kuchezwa kwenye kifaa chako. Hivyo kuwa mwangalifu na manenosiri, maelezo ya malipo, ujumbe au maelezo mengine nyeti."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Unaporekodi programu, Android inaweza kufikia kitu chochote kitakachoonekana au kuchezwa kwenye programu hiyo. Hivyo kuwa mwangalifu na manenosiri, maelezo ya malipo, ujumbe au maelezo mengine nyeti."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Anza kurekodi"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Rekodi sauti"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Sauti ya kifaa"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Sauti kutoka kwenye kifaa chako, kama vile muziki, simu na milio ya simu"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Huduma inayotoa utendaji huu itaweza kufikia maelezo yote yanayoonekana kwenye skrini yako au yanayochezwa kwenye kifaa chako wakati wa kurekodi au kutuma. Hii ni pamoja na maelezo kama vile manenosiri, maelezo ya malipo, picha, ujumbe na sauti unayocheza."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Ungependa kuanza kurekodi au kutuma?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Ungependa kuanza kurekodi au kutuma ukitumia <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Ungependa kuruhusu programu ya <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ishiriki au kurekodi?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Skrini nzima"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Programu moja"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Unapotuma, kurekodi au kushiriki, programu ya <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inaweza kufikia kitu chochote kitakachoonekana kwenye skrini yako au kuchezwa kwenye kifaa chako. Hivyo kuwa mwangalifu na manenosiri, maelezo ya malipo, ujumbe au maelezo mengine nyeti."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Unapotuma, kurekodi au kushiriki programu, programu ya <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inaweza kufikia kitu chochote kitakachoonekana au kuchezwa kwenye programu hiyo. Hivyo kuwa mwangalifu na manenosiri, maelezo ya malipo, ujumbe au maelezo mengine nyeti."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Endelea"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Shiriki au rekodi programu"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Futa zote"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Dhibiti"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 5dcbeb5..599bf30 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -68,6 +68,7 @@
     <dimen name="qs_security_footer_background_inset">0dp</dimen>
 
     <dimen name="qs_panel_padding_top">8dp</dimen>
+    <dimen name="qs_panel_padding_top_combined_headers">@dimen/qs_panel_padding_top</dimen>
 
     <!-- The width of large/content heavy dialogs (e.g. Internet, Media output, etc) -->
     <dimen name="large_dialog_width">472dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0550387..c823f04 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"திரை ரெக்கார்டிங் அமர்விற்கான தொடர் அறிவிப்பு"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ரெக்கார்டிங்கைத் தொடங்கவா?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ரெக்கார்டு செய்யும்போது, உங்கள் திரையில் தோன்றக்கூடிய அல்லது சாதனத்தில் பிளே ஆகக்கூடிய பாதுகாக்கப்பட வேண்டிய தகவலை Android சிஸ்டம் படமெடுக்க முடியும். கடவுச்சொற்கள், பேமெண்ட் தகவல், படங்கள், மெசேஜ்கள், ஆடியோ ஆகியவை இதில் அடங்கும்."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ஆடியோவை ரெக்கார்டு செய்"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"சாதன ஆடியோ"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"இசை, அழைப்புகள், ரிங்டோன்கள் போன்ற உங்கள் சாதனத்திலிருந்து வரும் ஒலி"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"இந்தச் செயல்பாட்டை வழங்கும் சேவையானது உங்கள் திரையில் தெரியும் தகவல்கள், ரெக்கார்டு செய்யும்போதோ அனுப்பும்போதோ உங்கள் சாதனத்திலிருந்து பிளே ஆகும் அனைத்துத் தகவல்கள் ஆகியவற்றுக்கான அணுகலைக் கொண்டிருக்கும். கடவுச்சொற்கள், பேமெண்ட் தொடர்பான தகவல்கள், படங்கள், மெசேஜ்கள், நீங்கள் பிளே செய்யும் ஆடியோ போன்ற அனைத்துத் தகவல்களும் இதில் அடங்கும்."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ரெக்கார்டிங் செய்யவோ அனுப்புவோ தொடங்கவா?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> மூலம் ரெக்கார்டிங் செய்யவோ அனுப்புவதற்கோ தொடங்கிவீட்டீர்களா?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"எல்லாவற்றையும் அழி"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"நிர்வகி"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"இதுவரை வந்த அறிவிப்புகள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 1e4fce6..42c24a2 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"స్క్రీన్ రికార్డ్ సెషన్ కోసం ఆన్‌గోయింగ్ నోటిఫికేషన్"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"రికార్డింగ్‌ను ప్రారంభించాలా?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"రికార్డ్ చేస్తున్నప్పుడు, Android సిస్టమ్ మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన ఏ సున్నితమైన సమాచారాన్నయినా క్యాప్చర్ చేయగలదు. ఈ సమాచారంలో పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు, మెసేజ్‌లు, ఆడియో కూడా ఉంటాయి."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"ఫుల్ స్క్రీన్ రికార్డ్ చేయండి"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"సింగిల్ యాప్ రికార్డ్ చేయండి"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"మీరు రికార్డ్ చేసేటప్పుడు, మీ స్క్రీన్‌పై కనిపించే దేనికైనా లేదా మీ పరికరంలో ప్లే అయిన దేనికైనా Androidకు యాక్సెస్ ఉంటుంది. కాబట్టి, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, లేదా ఏదైనా ఇతర సున్నితమైన సమాచారం పట్ల జాగ్రత్త వహించండి."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"మీరు యాప్‌ను రికార్డ్ చేసేటప్పుడు, ఆ యాప్‌లో చూపబడిన దేనికైనా లేదా ప్లే అయిన దేనికైనా Androidకు యాక్సెస్ ఉంటుంది. కాబట్టి, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, లేదా ఏదైనా ఇతర సున్నితమైన సమాచారం పట్ల జాగ్రత్త వహించండి."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"రికార్డింగ్‌ను ప్రారంభించండి"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"ఆడియోను రికార్డ్ చేయి"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"పరికరం ఆడియో"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"మీ పరికరం నుండి వచ్చే మ్యూజిక్, కాల్స్‌, రింగ్‌టోన్‌ల వంటి ధ్వనులు"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"రికార్డ్ చేస్తున్నప్పుడు లేదా ప్రసారం చేస్తున్నప్పుడు మీ స్క్రీన్‌పై ప్రదర్శించబడిన లేదా మీ పరికరం నుండి ప్లే చేయబడిన సమాచారం మొత్తాన్ని, ఈ ఫంక్షన్‌ను అందిస్తున్న సర్వీస్ యాక్సెస్ చేయగలదు. ఈ సమాచారంలో, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, ఫోటోలు,  మెసేజ్‌లు, మీరు ప్లే చేసే ఆడియో వంటివి ఉంటాయి."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>తో రికార్డ్ చేయడం లేదా ప్రసారం చేయడం ప్రారంభించాలా?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"షేర్ చేయడానికి లేదా రికార్డ్ చేయడానికి <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌ను అనుమతించాలా?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"ఫుల్-స్క్రీన్"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"సింగిల్ యాప్"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"మీరు షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, మీ స్క్రీన్‌పై కనిపించే దేనికైనా లేదా మీ పరికరంలో ప్లే అయిన దేనికైనా <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌కు యాక్సెస్ ఉంటుంది. కాబట్టి, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, లేదా ఏదైనా ఇతర సున్నితమైన సమాచారం పట్ల జాగ్రత్త వహించండి."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"మీరు ఏదైనా యాప్‌ను షేర్ చేస్తున్నప్పుడు, రికార్డ్ చేస్తున్నప్పుడు, లేదా ప్రసారం చేస్తున్నప్పుడు, ఆ యాప్‌లో చూపబడిన దేనికైనా లేదా ప్లే అయిన దేనికైనా <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>‌కు యాక్సెస్ ఉంటుంది. కాబట్టి, పాస్‌వర్డ్‌లు, పేమెంట్ వివరాలు, మెసేజ్‌లు, లేదా ఏదైనా ఇతర సున్నితమైన సమాచారం పట్ల జాగ్రత్త వహించండి."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"కొనసాగించండి"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"యాప్‌ను షేర్ చేయండి లేదా రికార్డ్ చేయండి"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"అన్నీ క్లియర్ చేయండి"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"మేనేజ్ చేయండి"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"హిస్టరీ"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e2e84d7..8078ac9 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"การแจ้งเตือนต่อเนื่องสำหรับเซสชันการบันทึกหน้าจอ"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"เริ่มบันทึกเลยไหม"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"ขณะบันทึก ระบบ Android อาจบันทึกข้อมูลที่ละเอียดอ่อนซึ่งปรากฏบนหน้าจอหรือเล่นในอุปกรณ์ได้ ซึ่งรวมถึงรหัสผ่าน ข้อมูลการชำระเงิน รูปภาพ ข้อความ และเสียง"</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"บันทึกทั้งหน้าจอ"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"บันทึกแอปเดียว"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"ขณะกำลังบันทึก Android จะมีสิทธิ์เข้าถึงทุกสิ่งที่ปรากฏบนหน้าจอหรือเล่นอยู่ในอุปกรณ์ ดังนั้นโปรดระวังเกี่ยวกับรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ"</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"ขณะกำลังบันทึกแอป Android จะมีสิทธิ์เข้าถึงทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังเกี่ยวกับรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"เริ่มบันทึก"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"บันทึกเสียง"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"เสียงจากอุปกรณ์"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"เสียงจากอุปกรณ์ เช่น เพลง การโทร และเสียงเรียกเข้า"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"บริการที่มีฟังก์ชันนี้จะมีสิทธิ์เข้าถึงข้อมูลทั้งหมดที่ปรากฏบนหน้าจอหรือเปิดจากอุปกรณ์ของคุณขณะบันทึกหรือแคสต์ ซึ่งรวมถึงข้อมูลอย่างเช่นรหัสผ่าน รายละเอียดการชำระเงิน รูปภาพ ข้อความ และเสียงที่คุณเล่น"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"เริ่มบันทึกหรือแคสต์ใช่ไหม"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"เริ่มบันทึกหรือแคสต์ด้วย <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> เลยไหม"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"อนุญาตให้ \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" แชร์หรือบันทึกไหม"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"ทั้งหน้าจอ"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"แอปเดียว"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"เมื่อกำลังแชร์ บันทึก หรือแคสต์ \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" จะมีสิทธิ์เข้าถึงทุกสิ่งที่ปรากฏบนหน้าจอหรือเล่นอยู่ในอุปกรณ์ ดังนั้นโปรดระวังเกี่ยวกับรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ"</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"เมื่อกำลังแชร์ บันทึก หรือแคสต์แอป \"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>\" จะมีสิทธิ์เข้าถึงทุกสิ่งที่แสดงหรือเล่นอยู่ในแอปดังกล่าว ดังนั้นโปรดระวังเกี่ยวกับรหัสผ่าน รายละเอียดการชำระเงิน ข้อความ หรือข้อมูลที่ละเอียดอ่อนอื่นๆ"</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"ต่อไป"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"แชร์หรือบันทึกแอป"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"ล้างทั้งหมด"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"จัดการ"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"ประวัติ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c32aa99..f8d42b2 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Kasalukuyang notification para sa session ng pag-record ng screen"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Simulang Mag-record?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Habang nagre-record, puwedeng ma-capture ng Android System ang anumang sensitibong impormasyong nakikita sa iyong screen o nagpe-play sa device mo. Kasama dito ang mga password, impormasyon sa pagbabayad, mga larawan, mensahe, at audio."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"I-record ang buong screen"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Mag-record ng isang app"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Habang nagre-record ka, may access ang Android sa kahit anong nakikita sa iyong screen o pine-play sa device mo. Kaya mag-ingat sa mga password, detalye ng pagbabayad, mensahe, o iba pang sensitibong impormasyon."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Habang nagre-record ka ng app, may access ang Android sa kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga password, detalye ng pagbabayad, mensahe, o iba pang sensitibong impormasyon."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Simulang mag-record"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Mag-record ng audio"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Audio ng device"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Tunog mula sa iyong device, gaya ng musika, mga tawag, at ringtone"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Ang serbisyong nagbibigay ng function na ito ay magkakaroon ng access sa lahat ng impormasyong nakikita sa iyong screen o pine-play mula sa device mo habang nagre-record o nagka-cast. Kasama rito ang impormasyong tulad ng mga password, detalye ng pagbabayad, larawan, mensahe, at audio na pine-play mo."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Magsimulang mag-record o mag-cast?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Simulang mag-record o mag-cast gamit ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Payagan ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> na magbahagi o mag-record?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Buong screen"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Isang app"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Kapag nagbabahagi, nagre-record, o nagka-cast ka, may access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa kahit anong nakikita sa iyong screen o pine-play sa device mo. Kaya mag-ingat sa mga password, detalye ng pagbabayad, mensahe, o iba pang sensitibong impormasyon."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Kapag nagbabahagi, nagre-record, o nagka-cast ka ng app, may access ang <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sa kahit anong ipinapakita o pine-play sa app na iyon. Kaya mag-ingat sa mga password, detalye ng pagbabayad, mensahe, o iba pang impormasyon."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Magpatuloy"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Ibahagi o i-record ang isang app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"I-clear lahat"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Pamahalaan"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d405540..e911bb2 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekran kaydı oturumu için devam eden bildirim"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Kayıt başlatılsın mı?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Kayıt sırasında Android Sistemi, ekranınızda görünen veya cihazınızda oynatılan hassas bilgileri yakalayabilir. Buna şifreler, ödeme bilgileri, fotoğraflar, mesajlar ve sesler dahildir."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Ses kaydet"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Cihaz sesi"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Müzik, aramalar, zil sesleri gibi cihazınızdan sesler"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Bu işlevi sağlayan hizmet, ekranınızda görünen veya kayıt ya da yayın sırasında cihazınızdan oynatılan tüm bilgilere erişecektir. Bu bilgiler arasında şifreler, ödeme detayları, fotoğraflar, mesajlar ve çaldığınız sesler gibi bilgiler yer alır."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Kayıt veya yayınlama başlatılsın mı?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ile kayıt veya yayınlama başlatılsın mı?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Tümünü temizle"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Yönet"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Geçmiş"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 58803f4..011c8bc 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Сповіщення про сеанс запису екрана"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Почати запис?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Під час запису система Android може фіксувати будь-яку конфіденційну інформацію, яка з\'являється на екрані або відтворюється на пристрої, зокрема паролі, платіжну інформацію, фотографії, повідомлення та звуки."</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Записувати звук"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Звук із пристрою"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Звук із пристрою, зокрема музика, виклики та сигнали дзвінка"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Сервіс, що надає цю функцію, матиме доступ до всієї інформації, яка з\'являється на екрані або відтворюється на пристрої під час запису чи трансляції, зокрема до паролів, інформації про платежі, фотографій, повідомлень і аудіофайлів."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Почати запис або трансляцію?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Почати запис або трансляцію за допомогою додатка <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Очистити все"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Керувати"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Історія"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 3472290..7d0df6c 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"اسکرین ریکارڈ سیشن کیلئے جاری اطلاع"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"ریکارڈنگ شروع کریں؟"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"‏ریکارڈ کرنے کے دوران، Android سسٹم آپ کی اسکرین پر نظر آنے والی یا آپ کے آلہ پر چلنے والی کسی بھی حساس معلومات کو کیپچر کر سکتا ہے۔ اس میں پاس ورڈز، ادائیگی کی معلومات، تصاویر، پیغامات اور آڈیو شامل ہیں۔"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"آڈیو ریکارڈ کریں"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"آلہ کا آڈیو"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"آپ کے آلے سے آواز، جیسے موسیقی، کالز اور رِنگ ٹونز"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"یہ فنکشن فراہم کرنے والی سروس کو اس تمام معلومات تک رسائی حاصل ہوگی جو آپ کی اسکرین پر نظر آتی ہے یا ریکارڈنگ یا کاسٹنگ کے دوران آپ کے آلے سے چلائی جاتی ہے۔ اس میں پاس ورڈز، ادائیگی کی تفصیلات، تصاویر، پیغامات اور وہ آڈیو جو آپ چلاتے ہیں جیسی معلومات شامل ہے۔"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"ریکارڈنگ یا کاسٹنگ شروع کریں؟"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> کے ذریعے ریکارڈنگ یا کاسٹنگ شروع کریں؟"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"سبھی کو صاف کریں"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"نظم کریں"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"سرگزشت"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 0102c3cb..3ab1a92 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Ekrandan yozib olish seansi uchun joriy bildirishnoma"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Yozib olish boshlansinmi?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Yozib olishda Android tizimi ekraningizda koʻringan yoki qurilmangizda ijro etilgan maxfiy axborotni ham yozib olishi mumkin. Bunga parollar, toʻlovga oid axborot, suratlar, xabarlar va audio kiradi."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Butun ekranni yozib olish"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Bitta ilovani yozib olish"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Yozib olish vaqtida Android ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar yoki boshqa maxfiy axborot chiqmasligi uchun ehtiyot boʻling."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Yozib olish vaqtida Android ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar yoki boshqa maxfiy axborot chiqmasligi uchun ehtiyot boʻling."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Yozib olish"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Audio yozib olish"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Qurilmadagi audio"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Qurilmangizdagi musiqa, chaqiruvlar va ringtonlar kabi ovozlar"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Bu funksiyani taʼminlovchi xizmat ekranda chiqqan yoki yozib olish va translatsiya vaqtida ijro etilgan barcha axborotlarga ruxsat oladi. Bu axborotlar parollar, toʻlov tafsilotlari, rasmlar, xabarlar va ijro etilgan audiolardan iborat boʻlishi mumkin."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Yozib olish yoki translatsiya boshlansinmi?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> orqali yozib olish yoki translatsiya boshlansinmi?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasida ulashish yoki yozib olish uchun ruxsat berilsinmi?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Butun ekran"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Bitta ilova"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Ulashish, yozib olish va translatsiya qilish vaqtida <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar yoki boshqa maxfiy axborot chiqmasligi uchun ehtiyot boʻling."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Ulashish, yozib olish va translatsiya qilish vaqtida <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> ilovasi ekranda chiqadigan yoki qurilmada ijro qilinadigan kontentni koʻra oladi. Shu sababli parollar, toʻlov tafsilotlari, xabarlar yoki boshqa maxfiy axborot chiqmasligi uchun ehtiyot boʻling."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Davom etish"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Ilovada ulashish yoki yozib olish"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Boshqarish"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarix"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f8b5491..022c081 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Thông báo đang diễn ra về phiên ghi màn hình"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Bắt đầu ghi?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Trong khi ghi, Hệ thống Android có thể ghi lại mọi thông tin nhạy cảm xuất hiện trên màn hình hoặc phát trên thiết bị của bạn. Những thông tin này bao gồm mật khẩu, thông tin thanh toán, ảnh, thông báo và âm thanh."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Ghi toàn màn hình"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Ghi một ứng dụng"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Khi bạn ghi, Android sẽ có quyền truy cập vào mọi nội dung xuất hiện trên màn hình hoặc phát trên thiết bị của bạn. Vì vậy, hãy thận trọng để không làm lộ mật khẩu, thông tin thanh toán, tin nhắn hoặc thông tin nhạy cảm khác."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Khi bạn ghi một ứng dụng, Android sẽ có quyền truy cập vào mọi nội dung xuất hiện hoặc phát trên thiết bị đó. Vì vậy, hãy thận trọng để không làm lộ mật khẩu, thông tin thanh toán, tin nhắn hoặc thông tin nhạy cảm khác."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Bắt đầu ghi"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Ghi âm"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Âm thanh trên thiết bị"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Âm thanh trên thiết bị, chẳng hạn như nhạc, cuộc gọi và nhạc chuông"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Dịch vụ cung cấp chức năng này có quyền truy cập vào tất cả các thông tin hiển thị trên màn hình của bạn hoặc phát trên thiết bị của bạn trong khi ghi âm/ghi hình hoặc truyền, bao gồm cả thông tin như mật khẩu, chi tiết thanh toán, ảnh, tin nhắn và âm thanh mà bạn phát."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Bắt đầu ghi âm/ghi hình hoặc truyền?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Bắt đầu ghi âm/ghi hình hoặc truyền bằng <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Cho phép <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> chia sẻ hoặc ghi?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Toàn màn hình"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"Một ứng dụng"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Khi bạn chia sẻ, ghi hoặc truyền, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào mọi nội dung xuất hiện trên màn hình hoặc phát trên thiết bị của bạn. Vì vậy, hãy thận trọng để không làm lộ mật khẩu, thông tin thanh toán, tin nhắn hoặc thông tin nhạy cảm khác."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Khi bạn chia sẻ, ghi hoặc truyền ứng dụng, <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> sẽ có quyền truy cập vào mọi nội dung xuất hiện hoặc phát trên ứng dụng đó. Vì vậy, hãy thận trọng để không làm lộ mật khẩu, thông tin thanh toán, tin nhắn hoặc thông tin nhạy cảm khác."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Tiếp tục"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Chia sẻ hoặc ghi ứng dụng"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Xóa tất cả"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Quản lý"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Lịch sử"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 5cb91978..d881fa2 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -94,6 +94,16 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"持续显示屏幕录制会话通知"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"要开始录制吗?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"在录制内容时,Android 系统可以捕捉到您屏幕上显示或设备中播放的敏感信息,其中包括密码、付款信息、照片、消息和音频。"</string>
+    <!-- no translation found for screenrecord_option_entire_screen (1732437834603426934) -->
+    <skip />
+    <!-- no translation found for screenrecord_option_single_app (5954863081500035825) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_entire_screen (8141407178104195610) -->
+    <skip />
+    <!-- no translation found for screenrecord_warning_single_app (7760723997065948283) -->
+    <skip />
+    <!-- no translation found for screenrecord_start_recording (348286842544768740) -->
+    <skip />
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"录制音频"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"设备音频"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"设备发出的声音,例如音乐、通话和铃声"</string>
@@ -361,6 +371,20 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"在录制或投放内容时,提供此功能的服务将可获取您屏幕上显示或设备中播放的所有信息,其中包括密码、付款明细、照片、消息以及您播放的音频等信息。"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"要开始录制或投放内容吗?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"要开始使用<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>录制或投放内容吗?"</string>
+    <!-- no translation found for media_projection_permission_dialog_title (7130975432309482596) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_entire_screen (392086473225692983) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_option_single_app (1591110238124910521) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_entire_screen (3989078820637452717) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_warning_single_app (1659532781536753059) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_dialog_continue (1827799658916736006) -->
+    <skip />
+    <!-- no translation found for media_projection_permission_app_selector_title (894251621057480704) -->
+    <skip />
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"历史记录"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index fd01945..d934786 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示錄影畫面工作階段通知"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"要開始錄製嗎?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"錄影時,Android 系統可擷取螢幕上顯示或裝置播放的任何敏感資料,包括密碼、付款資料、相片、訊息和音訊。"</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"錄製整個螢幕畫面"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"錄製單一應用程式"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"進行錄製時,Android 可以存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"錄製應用程式時,Android 可以存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"開始錄製"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"錄音"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"裝置音訊"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"裝置播放的音效,例如音樂、通話和鈴聲"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"在錄影或投放時,此功能的服務供應商可以存取螢幕顯示或裝置播放的任何資料,當中包括密碼、付款詳情、相片、訊息和播放的語音等。"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"要開始錄影或投放嗎?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"要使用「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」開始錄影或投放嗎?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"允許 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 分享或錄製?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"整個螢幕畫面"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"單一應用程式"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"進行分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"進行分享、錄製或投放應用程式時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"繼續"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或錄製應用程式"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 696b2d3..bbe4b6c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"持續顯示螢幕畫面錄製工作階段通知"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"要開始錄製嗎?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"錄製螢幕畫面時,Android 系統可擷取螢幕上顯示或裝置播放的任何機密資訊,包括密碼、付款資訊、相片、訊息和音訊。"</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"錄製整個螢幕畫面"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"錄製單一應用程式"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"進行錄製時,Android 可以存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"錄製應用程式時,Android 可以存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"開始錄製"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"錄音"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"裝置音訊"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"裝置所播放的音效,例如音樂、通話和鈴聲等等"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"在錄製或投放內容時,提供這項功能的服務可存取畫面上顯示的任何資訊或裝置播放的任何內容,包括密碼、付款詳情、相片、訊息和你播放的音訊。"</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"要開始錄製或投放內容嗎?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"要使用「<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>」開始錄製或投放內容嗎?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"允許 <xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 分享或錄製?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"整個螢幕畫面"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"單一應用程式"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"進行分享、錄製或投放時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取顯示在螢幕畫面上或在裝置上播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"進行分享、錄製或投放應用程式時,<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> 可以存取在該應用程式中顯示或播放的所有內容。因此請謹慎處理密碼、付款資料、訊息或其他機密資訊。"</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"繼續"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"分享或錄製應用程式"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"全部清除"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 751a45f..0ba0733a 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -94,6 +94,11 @@
     <string name="screenrecord_channel_description" msgid="4147077128486138351">"Isaziso esiqhubekayo seseshini yokurekhoda isikrini"</string>
     <string name="screenrecord_start_label" msgid="1750350278888217473">"Qala ukurekhoda?"</string>
     <string name="screenrecord_description" msgid="1123231719680353736">"Ngenkathi irekhoda, Isistimu ye-Android ingathatha noma iluphi ulwazi olubucayi olubonakal kusikrini sakho noma oludlalwa kudivayisi yakho. Lokhu kufaka phakathi amaphasiwedi, ulwazi lokukhokha, izithombe, imilayezo, nomsindo."</string>
+    <string name="screenrecord_option_entire_screen" msgid="1732437834603426934">"Rekhoda sonke isikrini"</string>
+    <string name="screenrecord_option_single_app" msgid="5954863081500035825">"Rekhoda i-app eyodwa"</string>
+    <string name="screenrecord_warning_entire_screen" msgid="8141407178104195610">"Ngenkathi urekhoda, i-Android inokufinyelela kunoma yini ebonakalayo esikrinini sakho noma edlalwa kudivayisi yakho. Ngakho-ke qaphela amagama ayimfihlo, imininingwane yokukhokha, imiyalezo, noma olunye ulwazi olubucayi."</string>
+    <string name="screenrecord_warning_single_app" msgid="7760723997065948283">"Ngenkathi urekhoda i-app, i-Android inokufinyelela kunoma yini eboniswayo noma edlalwayo kuleyo app. Ngakho-ke qaphela amagama ayimfihlo, imininingwane yokukhokha, imiyalezo, noma olunye ulwazi olubucayi."</string>
+    <string name="screenrecord_start_recording" msgid="348286842544768740">"Qala ukurekhoda"</string>
     <string name="screenrecord_audio_label" msgid="6183558856175159629">"Rekhoda umsindo"</string>
     <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Umsindo wedivayisi"</string>
     <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Umsindo ophuma kudivayisi yakho, njengomculo, amakholi, namathoni okukhala"</string>
@@ -361,6 +366,13 @@
     <string name="media_projection_dialog_service_text" msgid="958000992162214611">"Isevisi enikezela ngalo msebenzi izothola ukufinyelela kulo lonke ulwazi olubonakalayo esikrinini sakho noma oludlalwa kusuka kudivayisi yakho ngenkathi urekhoda noma usakaza. Lokhu kubandakanya ulwazi olufana namaphasiwedi, imininingwane yenkokhelo, izithombe, imilayezo, nomsindo owudlalayo."</string>
     <string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Qala ukurekhoda noma ukusakaza?"</string>
     <string name="media_projection_dialog_title" msgid="3316063622495360646">"Qala ukurekhoda noma ukusakaza nge-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g>?"</string>
+    <string name="media_projection_permission_dialog_title" msgid="7130975432309482596">"Vumela i-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> yabelane noma irekhode?"</string>
+    <string name="media_projection_permission_dialog_option_entire_screen" msgid="392086473225692983">"Sonke isikrini"</string>
+    <string name="media_projection_permission_dialog_option_single_app" msgid="1591110238124910521">"I-app eyodwa"</string>
+    <string name="media_projection_permission_dialog_warning_entire_screen" msgid="3989078820637452717">"Uma wabelana, urekhoda, noma usakaza, i-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inokufinyelela kunoma yini ebonakalayo kusikrini sakho noma edlalwa kudivayisi yakho. Ngakho-ke qaphela amagama ayimfihlo, imininingwane yokukhokha, imiyalezo, noma olunye ulwazi olubucayi."</string>
+    <string name="media_projection_permission_dialog_warning_single_app" msgid="1659532781536753059">"Uma wabelana, urekhoda, noma usakaza i-app, i-<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> inokufinyelela kunoma yini eboniswayo noma edlalwayo kuleyo app. Ngakho-ke qaphela amagama ayimfihlo, imininingwane yokukhokha, imiyalezo, noma olunye ulwazi olubucayi."</string>
+    <string name="media_projection_permission_dialog_continue" msgid="1827799658916736006">"Qhubeka"</string>
+    <string name="media_projection_permission_app_selector_title" msgid="894251621057480704">"Yabelana noma rekhoda i-app"</string>
     <string name="clear_all_notifications_text" msgid="348312370303046130">"Sula konke"</string>
     <string name="manage_notifications_text" msgid="6885645344647733116">"Phatha"</string>
     <string name="manage_notifications_history_text" msgid="57055985396576230">"Umlando"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 37549c9..9188ce0 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -337,9 +337,6 @@
      have been scrolled off-screen. -->
     <bool name="config_showNotificationShelf">true</bool>
 
-    <!-- Whether or not the notifications should always fade as they are dismissed. -->
-    <bool name="config_fadeNotificationsOnDismiss">false</bool>
-
     <!-- Whether or not the fade on the notification is based on the amount that it has been swiped
          off-screen. -->
     <bool name="config_fadeDependingOnAmountSwiped">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f7019dc..778dd45 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -559,7 +559,8 @@
     <dimen name="qs_dual_tile_padding_horizontal">6dp</dimen>
     <dimen name="qs_panel_elevation">4dp</dimen>
     <dimen name="qs_panel_padding_bottom">@dimen/footer_actions_height</dimen>
-    <dimen name="qs_panel_padding_top">80dp</dimen>
+    <dimen name="qs_panel_padding_top">48dp</dimen>
+    <dimen name="qs_panel_padding_top_combined_headers">80dp</dimen>
 
     <dimen name="qs_data_usage_text_size">14sp</dimen>
     <dimen name="qs_data_usage_usage_text_size">36sp</dimen>
@@ -1056,9 +1057,8 @@
     <!-- Media tap-to-transfer chip for receiver device -->
     <dimen name="media_ttt_chip_size_receiver">100dp</dimen>
     <dimen name="media_ttt_icon_size_receiver">95dp</dimen>
-    <!-- Since the generic icon isn't circular, we need to scale it down so it still fits within
-         the circular chip. -->
-    <dimen name="media_ttt_generic_icon_size_receiver">70dp</dimen>
+    <!-- Add some padding for the generic icon so it doesn't go all the way to the border. -->
+    <dimen name="media_ttt_generic_icon_padding">12dp</dimen>
     <dimen name="media_ttt_receiver_vert_translation">20dp</dimen>
 
     <!-- Window magnification -->
@@ -1457,6 +1457,9 @@
     <dimen name="media_projection_app_selector_icon_size">32dp</dimen>
     <dimen name="media_projection_app_selector_recents_padding">16dp</dimen>
     <dimen name="media_projection_app_selector_loader_size">32dp</dimen>
+    <dimen name="media_projection_app_selector_task_rounded_corners">10dp</dimen>
+    <dimen name="media_projection_app_selector_task_icon_size">24dp</dimen>
+    <dimen name="media_projection_app_selector_task_icon_margin">8dp</dimen>
 
     <!-- Dream overlay related dimensions -->
     <dimen name="dream_overlay_status_bar_height">60dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8084254..7ca42f7 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -131,6 +131,9 @@
     <!-- For StatusIconContainer to tag its icon views -->
     <item type="id" name="status_bar_view_state_tag" />
 
+    <!-- Status bar -->
+    <item type="id" name="status_bar_dot" />
+
     <!-- Default display cutout on the physical top of screen -->
     <item type="id" name="display_cutout" />
     <item type="id" name="display_cutout_left" />
@@ -185,5 +188,11 @@
     <item type="id" name="face_scanning_anim"/>
 
     <item type="id" name="qqs_tile_layout"/>
+
+    <!-- The buttons in the Quick Settings footer actions.-->
+    <item type="id" name="multi_user_switch"/>
+    <item type="id" name="pm_lite"/>
+    <item type="id" name="settings_button_container"/>
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53f1227..9b9111f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -246,6 +246,16 @@
     <string name="screenrecord_start_label">Start Recording?</string>
     <!-- Message reminding the user that sensitive information may be captured during a screen recording [CHAR_LIMIT=NONE]-->
     <string name="screenrecord_description">While recording, Android System can capture any sensitive information that\u2019s visible on your screen or played on your device. This includes passwords, payment info, photos, messages, and audio.</string>
+    <!-- Dropdown option to record the entire screen [CHAR_LIMIT=30]-->
+    <string name="screenrecord_option_entire_screen">Record entire screen</string>
+    <!-- Dropdown option to record a single app [CHAR_LIMIT=30]-->
+    <string name="screenrecord_option_single_app">Record a single app</string>
+    <!-- Message reminding the user that sensitive information may be captured during a full screen recording for the updated dialog that includes partial screen sharing option [CHAR_LIMIT=350]-->
+    <string name="screenrecord_warning_entire_screen">While you\'re recording, Android has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+    <!-- Message reminding the user that sensitive information may be captured during a single app screen recording for the updated dialog that includes partial screen sharing option [CHAR_LIMIT=350]-->
+    <string name="screenrecord_warning_single_app">While you\'re recording an app, Android has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+    <!-- Button to start a screen recording in the updated screen record dialog that allows to select an app to record [CHAR LIMIT=50]-->
+    <string name="screenrecord_start_recording">Start recording</string>
     <!-- Label for a switch to enable recording audio [CHAR LIMIT=NONE]-->
     <string name="screenrecord_audio_label">Record audio</string>
     <!-- Label for the option to record audio from the device [CHAR LIMIT=NONE]-->
@@ -958,7 +968,26 @@
     <!-- Media projection permission dialog warning title. [CHAR LIMIT=NONE] -->
     <string name="media_projection_dialog_title">Start recording or casting with <xliff:g id="app_seeking_permission" example="Hangouts">%s</xliff:g>?</string>
 
-    <!-- Media projection permission dialog permanent grant check box. [CHAR LIMIT=NONE] -->
+    <!-- Media projection permission dialog title. [CHAR LIMIT=NONE] -->
+    <string name="media_projection_permission_dialog_title">Allow <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> to share or record?</string>
+
+    <!-- Media projection permission dropdown option for capturing the whole screen. [CHAR LIMIT=30] -->
+    <string name="media_projection_permission_dialog_option_entire_screen">Entire screen</string>
+
+    <!-- Media projection permission dropdown option for capturing single app. [CHAR LIMIT=30] -->
+    <string name="media_projection_permission_dialog_option_single_app">A single app</string>
+
+    <!-- Media projection permission warning for capturing the whole screen. [CHAR LIMIT=350] -->
+    <string name="media_projection_permission_dialog_warning_entire_screen">When you\'re sharing, recording, or casting, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything visible on your screen or played on your device. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+
+    <!-- Media projection permission warning for capturing an app. [CHAR LIMIT=350] -->
+    <string name="media_projection_permission_dialog_warning_single_app">When you\'re sharing, recording, or casting an app, <xliff:g id="app_seeking_permission" example="Meet">%s</xliff:g> has access to anything shown or played on that app. So be careful with passwords, payment details, messages, or other sensitive information.</string>
+
+    <!-- Media projection permission button to continue with app selection or recording [CHAR LIMIT=60] -->
+    <string name="media_projection_permission_dialog_continue">Continue</string>
+
+    <!-- Title of the dialog that allows to select an app to share or record [CHAR LIMIT=NONE] -->
+    <string name="media_projection_permission_app_selector_title">Share or record an app</string>
 
     <!-- The text to clear all notifications. [CHAR LIMIT=60] -->
     <string name="clear_all_notifications_text">Clear all</string>
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 cdedc64..9766514 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
@@ -93,8 +93,8 @@
             Futures.addCallback(
                 captureToBitmap(window),
                 object : FutureCallback<Bitmap> {
-                    override fun onSuccess(result: Bitmap) {
-                        continuation.resumeWith(Result.success(result))
+                    override fun onSuccess(result: Bitmap?) {
+                        continuation.resumeWith(Result.success(result!!))
                     }
 
                     override fun onFailure(t: Throwable) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
index ffab3cd..12e0b9a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimator.kt
@@ -16,6 +16,7 @@
 package com.android.systemui.shared.animation
 
 import android.view.View
+import android.view.View.LAYOUT_DIRECTION_RTL
 import android.view.ViewGroup
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
@@ -58,9 +59,15 @@
         // progress == 0 -> -translationMax
         // progress == 1 -> 0
         val xTrans = (progress - 1f) * translationMax
+        val rtlMultiplier =
+            if (rootView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+                -1
+            } else {
+                1
+            }
         viewsToTranslate.forEach { (view, direction, shouldBeAnimated) ->
             if (shouldBeAnimated()) {
-                view.get()?.translationX = xTrans * direction.multiplier
+                view.get()?.translationX = xTrans * direction.multiplier * rtlMultiplier
             }
         }
     }
@@ -90,7 +97,7 @@
 
     /** Direction of the animation. */
     enum class Direction(val multiplier: Float) {
-        LEFT(-1f),
-        RIGHT(1f),
+        START(-1f),
+        END(1f),
     }
 }
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 c2e7445..860a5da 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
@@ -58,6 +58,7 @@
     private var lastOnTextChanged: CharSequence? = null
     private var lastInvalidate: CharSequence? = null
     private var lastTimeZoneChange: CharSequence? = null
+    private var lastAnimationCall: CharSequence? = null
 
     private val time = Calendar.getInstance()
 
@@ -222,6 +223,7 @@
     }
 
     fun animateAppearOnLockscreen() {
+        lastAnimationCall = "${getTimestamp()} call=animateAppearOnLockscreen"
         setTextStyle(
             weight = dozingWeight,
             textSize = -1f,
@@ -246,6 +248,7 @@
         if (isAnimationEnabled && textAnimator == null) {
             return
         }
+        lastAnimationCall = "${getTimestamp()} call=animateFoldAppear"
         setTextStyle(
             weight = lockScreenWeightInternal,
             textSize = -1f,
@@ -272,6 +275,7 @@
             // Skip charge animation if dozing animation is already playing.
             return
         }
+        lastAnimationCall = "${getTimestamp()} call=animateCharge"
         val startAnimPhase2 = Runnable {
             setTextStyle(
                 weight = if (isDozing()) dozingWeight else lockScreenWeight,
@@ -295,6 +299,7 @@
     }
 
     fun animateDoze(isDozing: Boolean, animate: Boolean) {
+        lastAnimationCall = "${getTimestamp()} call=animateDoze"
         setTextStyle(
             weight = if (isDozing) dozingWeight else lockScreenWeight,
             textSize = -1f,
@@ -408,6 +413,11 @@
         pw.println("    lastTimeZoneChange=$lastTimeZoneChange")
         pw.println("    currText=$text")
         pw.println("    currTimeContextDesc=$contentDescription")
+        pw.println("    lastAnimationCall=$lastAnimationCall")
+        pw.println("    dozingWeightInternal=$dozingWeightInternal")
+        pw.println("    lockScreenWeightInternal=$lockScreenWeightInternal")
+        pw.println("    dozingColor=$dozingColor")
+        pw.println("    lockScreenColor=$lockScreenColor")
         pw.println("    time=$time")
     }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
index 835d6e9..f03fee4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/ClockRegistry.kt
@@ -22,7 +22,7 @@
 import android.provider.Settings
 import android.util.Log
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.Clock
+import com.android.systemui.plugins.ClockController
 import com.android.systemui.plugins.ClockId
 import com.android.systemui.plugins.ClockMetadata
 import com.android.systemui.plugins.ClockProvider
@@ -33,7 +33,7 @@
 import javax.inject.Inject
 
 private val TAG = ClockRegistry::class.simpleName
-private val DEBUG = true
+private const val DEBUG = true
 
 /** ClockRegistry aggregates providers and plugins */
 open class ClockRegistry(
@@ -105,7 +105,8 @@
             )
         }
 
-        pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java)
+        pluginManager.addPluginListener(pluginListener, ClockProviderPlugin::class.java,
+            true /* allowMultiple */)
         context.contentResolver.registerContentObserver(
             Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
             false,
@@ -129,6 +130,10 @@
             }
 
             availableClocks[id] = ClockInfo(clock, provider)
+            if (DEBUG) {
+                Log.i(TAG, "Added ${clock.clockId}")
+            }
+
             if (currentId == id) {
                 if (DEBUG) {
                     Log.i(TAG, "Current clock ($currentId) was connected")
@@ -142,6 +147,9 @@
         val currentId = currentClockId
         for (clock in provider.getClocks()) {
             availableClocks.remove(clock.clockId)
+            if (DEBUG) {
+                Log.i(TAG, "Removed ${clock.clockId}")
+            }
 
             if (currentId == clock.clockId) {
                 Log.w(TAG, "Current clock ($currentId) was disconnected")
@@ -160,7 +168,7 @@
     fun getClockThumbnail(clockId: ClockId): Drawable? =
         availableClocks[clockId]?.provider?.getClockThumbnail(clockId)
 
-    fun createExampleClock(clockId: ClockId): Clock? = createClock(clockId)
+    fun createExampleClock(clockId: ClockId): ClockController? = createClock(clockId)
 
     fun registerClockChangeListener(listener: ClockChangeListener) =
         clockChangeListeners.add(listener)
@@ -168,11 +176,14 @@
     fun unregisterClockChangeListener(listener: ClockChangeListener) =
         clockChangeListeners.remove(listener)
 
-    fun createCurrentClock(): Clock {
+    fun createCurrentClock(): ClockController {
         val clockId = currentClockId
         if (isEnabled && clockId.isNotEmpty()) {
             val clock = createClock(clockId)
             if (clock != null) {
+                if (DEBUG) {
+                    Log.i(TAG, "Rendering clock $clockId")
+                }
                 return clock
             } else {
                 Log.e(TAG, "Clock $clockId not found; using default")
@@ -182,7 +193,7 @@
         return createClock(DEFAULT_CLOCK_ID)!!
     }
 
-    private fun createClock(clockId: ClockId): Clock? =
+    private fun createClock(clockId: ClockId): ClockController? =
         availableClocks[clockId]?.provider?.createClock(clockId)
 
     private data class ClockInfo(
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt
new file mode 100644
index 0000000..b887951
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 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.clocks
+
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Color
+import android.icu.text.NumberFormat
+import android.util.TypedValue
+import android.view.LayoutInflater
+import android.widget.FrameLayout
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.plugins.ClockAnimations
+import com.android.systemui.plugins.ClockController
+import com.android.systemui.plugins.ClockEvents
+import com.android.systemui.plugins.ClockFaceController
+import com.android.systemui.plugins.ClockFaceEvents
+import com.android.systemui.shared.R
+import java.io.PrintWriter
+import java.util.Locale
+import java.util.TimeZone
+
+private val TAG = DefaultClockController::class.simpleName
+
+/**
+ * Controls the default clock visuals.
+ *
+ * This serves as an adapter between the clock interface and the AnimatableClockView used by the
+ * existing lockscreen clock.
+ */
+class DefaultClockController(
+    ctx: Context,
+    private val layoutInflater: LayoutInflater,
+    private val resources: Resources,
+) : ClockController {
+    override val smallClock: DefaultClockFaceController
+    override val largeClock: LargeClockFaceController
+    private val clocks: List<AnimatableClockView>
+
+    private val burmeseNf = NumberFormat.getInstance(Locale.forLanguageTag("my"))
+    private val burmeseNumerals = burmeseNf.format(FORMAT_NUMBER.toLong())
+    private val burmeseLineSpacing =
+        resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese)
+    private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale)
+
+    override val events: DefaultClockEvents
+    override lateinit var animations: DefaultClockAnimations
+        private set
+
+    init {
+        val parent = FrameLayout(ctx)
+        smallClock =
+            DefaultClockFaceController(
+                layoutInflater.inflate(R.layout.clock_default_small, parent, false)
+                    as AnimatableClockView
+            )
+        largeClock =
+            LargeClockFaceController(
+                layoutInflater.inflate(R.layout.clock_default_large, parent, false)
+                    as AnimatableClockView
+            )
+        clocks = listOf(smallClock.view, largeClock.view)
+
+        events = DefaultClockEvents()
+        animations = DefaultClockAnimations(0f, 0f)
+        events.onLocaleChanged(Locale.getDefault())
+    }
+
+    override fun initialize(resources: Resources, dozeFraction: Float, foldFraction: Float) {
+        largeClock.recomputePadding()
+        animations = DefaultClockAnimations(dozeFraction, foldFraction)
+        events.onColorPaletteChanged(resources)
+        events.onTimeZoneChanged(TimeZone.getDefault())
+        events.onTimeTick()
+    }
+
+    open inner class DefaultClockFaceController(
+        override val view: AnimatableClockView,
+    ) : ClockFaceController {
+        // MAGENTA is a placeholder, and will be assigned correctly in initialize
+        private var currentColor = Color.MAGENTA
+        private var isRegionDark = false
+
+        init {
+            view.setColors(currentColor, currentColor)
+        }
+
+        override val events =
+            object : ClockFaceEvents {
+                override fun onRegionDarknessChanged(isRegionDark: Boolean) {
+                    this@DefaultClockFaceController.isRegionDark = isRegionDark
+                    updateColor()
+                }
+            }
+
+        fun updateColor() {
+            val color =
+                if (isRegionDark) {
+                    resources.getColor(android.R.color.system_accent1_100)
+                } else {
+                    resources.getColor(android.R.color.system_accent2_600)
+                }
+
+            if (currentColor == color) {
+                return
+            }
+
+            currentColor = color
+            view.setColors(DOZE_COLOR, color)
+            view.animateAppearOnLockscreen()
+        }
+    }
+
+    inner class LargeClockFaceController(
+        view: AnimatableClockView,
+    ) : DefaultClockFaceController(view) {
+        fun recomputePadding() {
+            val lp = view.getLayoutParams() as FrameLayout.LayoutParams
+            lp.topMargin = (-0.5f * view.bottom).toInt()
+            view.setLayoutParams(lp)
+        }
+    }
+
+    inner class DefaultClockEvents : ClockEvents {
+        override fun onTimeTick() = clocks.forEach { it.refreshTime() }
+
+        override fun onTimeFormatChanged(is24Hr: Boolean) =
+            clocks.forEach { it.refreshFormat(is24Hr) }
+
+        override fun onTimeZoneChanged(timeZone: TimeZone) =
+            clocks.forEach { it.onTimeZoneChanged(timeZone) }
+
+        override fun onFontSettingChanged() {
+            smallClock.view.setTextSize(
+                TypedValue.COMPLEX_UNIT_PX,
+                resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
+            )
+            largeClock.view.setTextSize(
+                TypedValue.COMPLEX_UNIT_PX,
+                resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
+            )
+            largeClock.recomputePadding()
+        }
+
+        override fun onColorPaletteChanged(resources: Resources) {
+            largeClock.updateColor()
+            smallClock.updateColor()
+        }
+
+        override fun onLocaleChanged(locale: Locale) {
+            val nf = NumberFormat.getInstance(locale)
+            if (nf.format(FORMAT_NUMBER.toLong()) == burmeseNumerals) {
+                clocks.forEach { it.setLineSpacingScale(burmeseLineSpacing) }
+            } else {
+                clocks.forEach { it.setLineSpacingScale(defaultLineSpacing) }
+            }
+
+            clocks.forEach { it.refreshFormat() }
+        }
+    }
+
+    inner class DefaultClockAnimations(
+        dozeFraction: Float,
+        foldFraction: Float,
+    ) : ClockAnimations {
+        private var foldState = AnimationState(0f)
+        private var dozeState = AnimationState(0f)
+
+        init {
+            dozeState = AnimationState(dozeFraction)
+            foldState = AnimationState(foldFraction)
+
+            if (foldState.isActive) {
+                clocks.forEach { it.animateFoldAppear(false) }
+            } else {
+                clocks.forEach { it.animateDoze(dozeState.isActive, false) }
+            }
+        }
+
+        override fun enter() {
+            if (!dozeState.isActive) {
+                clocks.forEach { it.animateAppearOnLockscreen() }
+            }
+        }
+
+        override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } }
+
+        override fun fold(fraction: Float) {
+            val (hasChanged, hasJumped) = foldState.update(fraction)
+            if (hasChanged) {
+                clocks.forEach { it.animateFoldAppear(!hasJumped) }
+            }
+        }
+
+        override fun doze(fraction: Float) {
+            val (hasChanged, hasJumped) = dozeState.update(fraction)
+            if (hasChanged) {
+                clocks.forEach { it.animateDoze(dozeState.isActive, !hasJumped) }
+            }
+        }
+    }
+
+    private class AnimationState(
+        var fraction: Float,
+    ) {
+        var isActive: Boolean = fraction < 0.5f
+        fun update(newFraction: Float): Pair<Boolean, Boolean> {
+            val wasActive = isActive
+            val hasJumped =
+                (fraction == 0f && newFraction == 1f) || (fraction == 1f && newFraction == 0f)
+            isActive = newFraction > fraction
+            fraction = newFraction
+            return Pair(wasActive != isActive, hasJumped)
+        }
+    }
+
+    override fun dump(pw: PrintWriter) {
+        pw.print("smallClock=")
+        smallClock.view.dump(pw)
+
+        pw.print("largeClock=")
+        largeClock.view.dump(pw)
+    }
+
+    companion object {
+        @VisibleForTesting const val DOZE_COLOR = Color.WHITE
+        private const val FORMAT_NUMBER = 1234567890
+    }
+}
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 19ac2e4..6627c5d 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
@@ -15,24 +15,14 @@
 
 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
-import com.android.systemui.plugins.ClockEvents
+import com.android.systemui.plugins.ClockController
 import com.android.systemui.plugins.ClockId
 import com.android.systemui.plugins.ClockMetadata
 import com.android.systemui.plugins.ClockProvider
 import com.android.systemui.shared.R
-import java.io.PrintWriter
-import java.util.Locale
-import java.util.TimeZone
 import javax.inject.Inject
 
 private val TAG = DefaultClockProvider::class.simpleName
@@ -48,11 +38,12 @@
     override fun getClocks(): List<ClockMetadata> =
         listOf(ClockMetadata(DEFAULT_CLOCK_ID, DEFAULT_CLOCK_NAME))
 
-    override fun createClock(id: ClockId): Clock {
+    override fun createClock(id: ClockId): ClockController {
         if (id != DEFAULT_CLOCK_ID) {
             throw IllegalArgumentException("$id is unsupported by $TAG")
         }
-        return DefaultClock(ctx, layoutInflater, resources)
+
+        return DefaultClockController(ctx, layoutInflater, resources)
     }
 
     override fun getClockThumbnail(id: ClockId): Drawable? {
@@ -64,190 +55,3 @@
         return resources.getDrawable(R.drawable.clock_default_thumbnail, null)
     }
 }
-
-/**
- * Controls the default clock visuals.
- *
- * This serves as an adapter between the clock interface and the
- * AnimatableClockView used by the existing lockscreen clock.
- */
-class DefaultClock(
-        ctx: Context,
-        private val layoutInflater: LayoutInflater,
-        private val resources: Resources
-) : Clock {
-    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())
-    private val burmeseLineSpacing =
-        resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale_burmese)
-    private val defaultLineSpacing = resources.getFloat(R.dimen.keyguard_clock_line_spacing_scale)
-
-    override val events: ClockEvents
-    override lateinit var animations: ClockAnimations
-        private set
-
-    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 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) =
-            clocks.forEach { it.refreshFormat(is24Hr) }
-
-        override fun onTimeZoneChanged(timeZone: TimeZone) =
-            clocks.forEach { it.onTimeZoneChanged(timeZone) }
-
-        override fun onFontSettingChanged() {
-            smallClock.setTextSize(
-                TypedValue.COMPLEX_UNIT_PX,
-                resources.getDimensionPixelSize(R.dimen.small_clock_text_size).toFloat()
-            )
-            largeClock.setTextSize(
-                TypedValue.COMPLEX_UNIT_PX,
-                resources.getDimensionPixelSize(R.dimen.large_clock_text_size).toFloat()
-            )
-            recomputePadding()
-        }
-
-        override fun onColorPaletteChanged(
-                resources: Resources,
-                smallClockIsDark: Boolean,
-                largeClockIsDark: Boolean
-        ) {
-            if (smallRegionDarkness != smallClockIsDark) {
-                smallRegionDarkness = smallClockIsDark
-                updateClockColor(smallClock, smallClockIsDark)
-            }
-            if (largeRegionDarkness != largeClockIsDark) {
-                largeRegionDarkness = largeClockIsDark
-                updateClockColor(largeClock, largeClockIsDark)
-            }
-        }
-
-        override fun onLocaleChanged(locale: Locale) {
-            val nf = NumberFormat.getInstance(locale)
-            if (nf.format(FORMAT_NUMBER.toLong()) == burmeseNumerals) {
-                clocks.forEach { it.setLineSpacingScale(burmeseLineSpacing) }
-            } else {
-                clocks.forEach { it.setLineSpacingScale(defaultLineSpacing) }
-            }
-
-            clocks.forEach { it.refreshFormat() }
-        }
-    }
-
-    inner class DefaultClockAnimations(
-        dozeFraction: Float,
-        foldFraction: Float
-    ) : ClockAnimations {
-        private var foldState = AnimationState(0f)
-        private var dozeState = AnimationState(0f)
-
-        init {
-            dozeState = AnimationState(dozeFraction)
-            foldState = AnimationState(foldFraction)
-
-            if (foldState.isActive) {
-                clocks.forEach { it.animateFoldAppear(false) }
-            } else {
-                clocks.forEach { it.animateDoze(dozeState.isActive, false) }
-            }
-        }
-
-        override fun enter() {
-            if (!dozeState.isActive) {
-                clocks.forEach { it.animateAppearOnLockscreen() }
-            }
-        }
-
-        override fun charge() = clocks.forEach { it.animateCharge { dozeState.isActive } }
-
-        override fun fold(fraction: Float) {
-            val (hasChanged, hasJumped) = foldState.update(fraction)
-            if (hasChanged) {
-                clocks.forEach { it.animateFoldAppear(!hasJumped) }
-            }
-        }
-
-        override fun doze(fraction: Float) {
-            val (hasChanged, hasJumped) = dozeState.update(fraction)
-            if (hasChanged) {
-                clocks.forEach { it.animateDoze(dozeState.isActive, !hasJumped) }
-            }
-        }
-    }
-
-    private class AnimationState(
-        var fraction: Float
-    ) {
-        var isActive: Boolean = fraction < 0.5f
-        fun update(newFraction: Float): Pair<Boolean, Boolean> {
-            val wasActive = isActive
-            val hasJumped = (fraction == 0f && newFraction == 1f) ||
-                (fraction == 1f && newFraction == 0f)
-            isActive = newFraction > fraction
-            fraction = newFraction
-            return Pair(wasActive != isActive, hasJumped)
-        }
-    }
-
-    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 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 {
-        @VisibleForTesting const val DOZE_COLOR = Color.WHITE
-        private const val FORMAT_NUMBER = 1234567890
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index c7d5ffe..023ef31 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -217,12 +217,16 @@
                 unregisterSamplingListener();
                 mSamplingListenerRegistered = true;
                 SurfaceControl wrappedStopLayer = wrap(stopLayerControl);
+
+                // pass this to background thread to avoid empty Rect race condition
+                final Rect boundsCopy = new Rect(mSamplingRequestBounds);
+
                 mBackgroundExecutor.execute(() -> {
                     if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
                         return;
                     }
                     mCompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
-                            wrappedStopLayer, mSamplingRequestBounds);
+                            wrappedStopLayer, boundsCopy);
                 });
                 mRegisteredSamplingBounds.set(mSamplingRequestBounds);
                 mRegisteredStopLayer = stopLayerControl;
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 e77c650..2b2b05ce 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
@@ -81,11 +81,6 @@
      */
     void stopScreenPinning() = 17;
 
-    /*
-     * Notifies that the swipe-to-home (recents animation) is finished.
-     */
-    void notifySwipeToHomeFinished() = 23;
-
     /**
      * Notifies that quickstep will switch to a new task
      * @param rotation indicates which Surface.Rotation the gesture was started in
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index 4222744..2111df5 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -237,6 +237,13 @@
     public ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData lastSnapshotData =
             new ActivityManager.RecentTaskInfo.PersistedTaskSnapshotData();
 
+    /**
+     * Indicates that this task for the desktop tile in recents.
+     *
+     * Used when desktop mode feature is enabled.
+     */
+    public boolean desktopTile;
+
     public Task() {
         // Do nothing
     }
@@ -267,6 +274,7 @@
         this(other.key, other.colorPrimary, other.colorBackground, other.isDockable,
                 other.isLocked, other.taskDescription, other.topActivity);
         lastSnapshotData.set(other.lastSnapshotData);
+        desktopTile = other.desktopTile;
     }
 
     /**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
new file mode 100644
index 0000000..72f8b7b
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
@@ -0,0 +1,209 @@
+package com.android.systemui.shared.recents.utilities;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.Surface;
+
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+/**
+ * Utility class to position the thumbnail in the TaskView
+ */
+public class PreviewPositionHelper {
+
+    public static final float MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT = 0.1f;
+
+    // Contains the portion of the thumbnail that is unclipped when fullscreen progress = 1.
+    private final RectF mClippedInsets = new RectF();
+    private final Matrix mMatrix = new Matrix();
+    private boolean mIsOrientationChanged;
+
+    public Matrix getMatrix() {
+        return mMatrix;
+    }
+
+    public void setOrientationChanged(boolean orientationChanged) {
+        mIsOrientationChanged = orientationChanged;
+    }
+
+    public boolean isOrientationChanged() {
+        return mIsOrientationChanged;
+    }
+
+    /**
+     * Updates the matrix based on the provided parameters
+     */
+    public void updateThumbnailMatrix(Rect thumbnailBounds, ThumbnailData thumbnailData,
+            int canvasWidth, int canvasHeight, int screenWidthPx, int taskbarSize, boolean isTablet,
+            int currentRotation, boolean isRtl) {
+        boolean isRotated = false;
+        boolean isOrientationDifferent;
+
+        int thumbnailRotation = thumbnailData.rotation;
+        int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
+        RectF thumbnailClipHint = new RectF();
+        float canvasScreenRatio = canvasWidth / (float) screenWidthPx;
+        float scaledTaskbarSize = taskbarSize * canvasScreenRatio;
+        thumbnailClipHint.bottom = isTablet ? scaledTaskbarSize : 0;
+
+        float scale = thumbnailData.scale;
+        final float thumbnailScale;
+
+        // Landscape vs portrait change.
+        // Note: Disable rotation in grid layout.
+        boolean windowingModeSupportsRotation =
+                thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN && !isTablet;
+        isOrientationDifferent = isOrientationChange(deltaRotate)
+                && windowingModeSupportsRotation;
+        if (canvasWidth == 0 || canvasHeight == 0 || scale == 0) {
+            // If we haven't measured , skip the thumbnail drawing and only draw the background
+            // color
+            thumbnailScale = 0f;
+        } else {
+            // Rotate the screenshot if not in multi-window mode
+            isRotated = deltaRotate > 0 && windowingModeSupportsRotation;
+
+            float surfaceWidth = thumbnailBounds.width() / scale;
+            float surfaceHeight = thumbnailBounds.height() / scale;
+            float availableWidth = surfaceWidth
+                    - (thumbnailClipHint.left + thumbnailClipHint.right);
+            float availableHeight = surfaceHeight
+                    - (thumbnailClipHint.top + thumbnailClipHint.bottom);
+
+            float canvasAspect = canvasWidth / (float) canvasHeight;
+            float availableAspect = isRotated
+                    ? availableHeight / availableWidth
+                    : availableWidth / availableHeight;
+            boolean isAspectLargelyDifferent =
+                    Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
+                            availableAspect, MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT);
+            if (isRotated && isAspectLargelyDifferent) {
+                // Do not rotate thumbnail if it would not improve fit
+                isRotated = false;
+                isOrientationDifferent = false;
+            }
+
+            if (isAspectLargelyDifferent) {
+                // Crop letterbox insets if insets isn't already clipped
+                thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
+                thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
+                thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
+                thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
+                availableWidth = surfaceWidth
+                        - (thumbnailClipHint.left + thumbnailClipHint.right);
+                availableHeight = surfaceHeight
+                        - (thumbnailClipHint.top + thumbnailClipHint.bottom);
+            }
+
+            final float targetW, targetH;
+            if (isOrientationDifferent) {
+                targetW = canvasHeight;
+                targetH = canvasWidth;
+            } else {
+                targetW = canvasWidth;
+                targetH = canvasHeight;
+            }
+            float targetAspect = targetW / targetH;
+
+            // Update the clipHint such that
+            //   > the final clipped position has same aspect ratio as requested by canvas
+            //   > first fit the width and crop the extra height
+            //   > if that will leave empty space, fit the height and crop the width instead
+            float croppedWidth = availableWidth;
+            float croppedHeight = croppedWidth / targetAspect;
+            if (croppedHeight > availableHeight) {
+                croppedHeight = availableHeight;
+                if (croppedHeight < targetH) {
+                    croppedHeight = Math.min(targetH, surfaceHeight);
+                }
+                croppedWidth = croppedHeight * targetAspect;
+
+                // One last check in case the task aspect radio messed up something
+                if (croppedWidth > surfaceWidth) {
+                    croppedWidth = surfaceWidth;
+                    croppedHeight = croppedWidth / targetAspect;
+                }
+            }
+
+            // Update the clip hints. Align to 0,0, crop the remaining.
+            if (isRtl) {
+                thumbnailClipHint.left += availableWidth - croppedWidth;
+                if (thumbnailClipHint.right < 0) {
+                    thumbnailClipHint.left += thumbnailClipHint.right;
+                    thumbnailClipHint.right = 0;
+                }
+            } else {
+                thumbnailClipHint.right += availableWidth - croppedWidth;
+                if (thumbnailClipHint.left < 0) {
+                    thumbnailClipHint.right += thumbnailClipHint.left;
+                    thumbnailClipHint.left = 0;
+                }
+            }
+            thumbnailClipHint.bottom += availableHeight - croppedHeight;
+            if (thumbnailClipHint.top < 0) {
+                thumbnailClipHint.bottom += thumbnailClipHint.top;
+                thumbnailClipHint.top = 0;
+            } else if (thumbnailClipHint.bottom < 0) {
+                thumbnailClipHint.top += thumbnailClipHint.bottom;
+                thumbnailClipHint.bottom = 0;
+            }
+
+            thumbnailScale = targetW / (croppedWidth * scale);
+        }
+
+        if (!isRotated) {
+            mMatrix.setTranslate(
+                    -thumbnailClipHint.left * scale,
+                    -thumbnailClipHint.top * scale);
+        } else {
+            setThumbnailRotation(deltaRotate, thumbnailBounds);
+        }
+
+        mClippedInsets.set(0, 0, 0, scaledTaskbarSize);
+
+        mMatrix.postScale(thumbnailScale, thumbnailScale);
+        mIsOrientationChanged = isOrientationDifferent;
+    }
+
+    private int getRotationDelta(int oldRotation, int newRotation) {
+        int delta = newRotation - oldRotation;
+        if (delta < 0) delta += 4;
+        return delta;
+    }
+
+    /**
+     * @param deltaRotation the number of 90 degree turns from the current orientation
+     * @return {@code true} if the change in rotation results in a shift from landscape to
+     * portrait or vice versa, {@code false} otherwise
+     */
+    private boolean isOrientationChange(int deltaRotation) {
+        return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270;
+    }
+
+    private void setThumbnailRotation(int deltaRotate, Rect thumbnailPosition) {
+        float translateX = 0;
+        float translateY = 0;
+
+        mMatrix.setRotate(90 * deltaRotate);
+        switch (deltaRotate) { /* Counter-clockwise */
+            case Surface.ROTATION_90:
+                translateX = thumbnailPosition.height();
+                break;
+            case Surface.ROTATION_270:
+                translateY = thumbnailPosition.width();
+                break;
+            case Surface.ROTATION_180:
+                translateX = thumbnailPosition.width();
+                translateY = thumbnailPosition.height();
+                break;
+        }
+        mMatrix.postTranslate(translateX, translateY);
+    }
+
+    public RectF getClippedInsets() {
+        return mClippedInsets;
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
index 56326e3..77a13bd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/Utilities.java
@@ -62,6 +62,16 @@
         return false; // Default
     }
 
+    /**
+     * Compares the ratio of two quantities and returns whether that ratio is greater than the
+     * provided bound. Order of quantities does not matter. Bound should be a decimal representation
+     * of a percentage.
+     */
+    public static boolean isRelativePercentDifferenceGreaterThan(float first, float second,
+            float bound) {
+        return (Math.abs(first - second) / Math.abs((first + second) / 2.0f)) > bound;
+    }
+
     /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
     public static float computeContrastBetweenColors(int bg, int fg) {
         float bgR = Color.red(bg) / 255f;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 916526d..ce337bb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -19,7 +19,6 @@
 import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 import static android.app.ActivityTaskManager.getService;
 
 import android.annotation.NonNull;
@@ -27,7 +26,6 @@
 import android.app.Activity;
 import android.app.ActivityClient;
 import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
@@ -252,8 +250,9 @@
     public boolean startActivityFromRecents(int taskId, ActivityOptions options) {
         try {
             Bundle optsBundle = options == null ? null : options.toBundle();
-            getService().startActivityFromRecents(taskId, optsBundle);
-            return true;
+            return ActivityManager.isStartResultSuccessful(
+                    getService().startActivityFromRecents(
+                            taskId, optsBundle));
         } catch (Exception e) {
             return false;
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 6d12485..f2742b7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -43,25 +43,8 @@
     public static final String KEY_EXTRA_SYSUI_PROXY = "extra_sysui_proxy";
     public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius";
     public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
-    // See IPip.aidl
-    public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
-    // See ISplitScreen.aidl
-    public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
-    // See IFloatingTasks.aidl
-    public static final String KEY_EXTRA_SHELL_FLOATING_TASKS = "extra_shell_floating_tasks";
-    // See IOneHanded.aidl
-    public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
-    // See IShellTransitions.aidl
-    public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
-            "extra_shell_shell_transitions";
-    // See IStartingWindow.aidl
-    public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
-            "extra_shell_starting_window";
     // See ISysuiUnlockAnimationController.aidl
     public static final String KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER = "unlock_animation";
-    // See IRecentTasks.aidl
-    public static final String KEY_EXTRA_RECENT_TASKS = "recent_tasks";
-    public static final String KEY_EXTRA_SHELL_BACK_ANIMATION = "extra_shell_back_animation";
 
     public static final String NAV_BAR_MODE_3BUTTON_OVERLAY =
             WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY;
diff --git a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
index 74bd9c6..bb3df8f 100644
--- a/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-debug/com/android/systemui/flags/FlagsModule.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.os.Handler
+import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlagsDebug.ALL_FLAGS
 import com.android.systemui.util.settings.SettingsUtilModule
@@ -27,6 +28,7 @@
 import javax.inject.Named
 
 @Module(includes = [
+    FeatureFlagsDebugStartableModule::class,
     ServerFlagReaderModule::class,
     SettingsUtilModule::class,
 ])
@@ -46,5 +48,15 @@
         @Provides
         @Named(ALL_FLAGS)
         fun providesAllFlags(): Map<Int, Flag<*>> = Flags.collectFlags()
+
+        @JvmStatic
+        @Provides
+        fun providesRestarter(barService: IStatusBarService): Restarter {
+            return object: Restarter {
+                override fun restart() {
+                    barService.restart()
+                }
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
index 38b5c9a..0f7e732 100644
--- a/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
+++ b/packages/SystemUI/src-release/com/android/systemui/flags/FlagsModule.kt
@@ -16,11 +16,29 @@
 
 package com.android.systemui.flags
 
+import com.android.internal.statusbar.IStatusBarService
 import dagger.Binds
 import dagger.Module
+import dagger.Provides
 
-@Module(includes = [ServerFlagReaderModule::class])
+@Module(includes = [
+    FeatureFlagsReleaseStartableModule::class,
+    ServerFlagReaderModule::class
+])
 abstract class FlagsModule {
     @Binds
     abstract fun bindsFeatureFlagRelease(impl: FeatureFlagsRelease): FeatureFlags
+
+    @Module
+    companion object {
+        @JvmStatic
+        @Provides
+        fun providesRestarter(barService: IStatusBarService): Restarter {
+            return object: Restarter {
+                override fun restart() {
+                    barService.restart()
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index 907943a..7971e84 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -293,7 +293,7 @@
     }
 
     protected List<SubscriptionInfo> getSubscriptionInfo() {
-        return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
+        return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo();
     }
 
     protected void updateCarrierText() {
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index b444f4c..9151238 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -27,7 +27,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.plugins.Clock
+import com.android.systemui.plugins.ClockController
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shared.regionsampling.RegionSamplingInstance
 import com.android.systemui.statusbar.policy.BatteryController
@@ -44,18 +44,18 @@
  * [KeyguardClockSwitchController]. Functionality is forked from [AnimatableClockController].
  */
 open class ClockEventController @Inject constructor(
-        private val statusBarStateController: StatusBarStateController,
-        private val broadcastDispatcher: BroadcastDispatcher,
-        private val batteryController: BatteryController,
-        private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-        private val configurationController: ConfigurationController,
-        @Main private val resources: Resources,
-        private val context: Context,
-        @Main private val mainExecutor: Executor,
-        @Background private val bgExecutor: Executor,
-        private val featureFlags: FeatureFlags
+    private val statusBarStateController: StatusBarStateController,
+    private val broadcastDispatcher: BroadcastDispatcher,
+    private val batteryController: BatteryController,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    private val configurationController: ConfigurationController,
+    @Main private val resources: Resources,
+    private val context: Context,
+    @Main private val mainExecutor: Executor,
+    @Background private val bgExecutor: Executor,
+    private val featureFlags: FeatureFlags,
 ) {
-    var clock: Clock? = null
+    var clock: ClockController? = null
         set(value) {
             field = value
             if (value != null) {
@@ -69,47 +69,50 @@
 
     private var isCharging = false
     private var dozeAmount = 0f
-    private var isKeyguardShowing = false
+    private var isKeyguardVisible = false
 
     private val regionSamplingEnabled =
             featureFlags.isEnabled(com.android.systemui.flags.Flags.REGION_SAMPLING)
 
-    private val updateFun = object : RegionSamplingInstance.UpdateColorCallback {
-        override fun updateColors() {
-            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)
+    private fun updateColors() {
+        if (regionSamplingEnabled && smallRegionSampler != null && largeRegionSampler != null) {
+            smallClockIsDark = smallRegionSampler!!.currentRegionDarkness().isDark
+            largeClockIsDark = largeRegionSampler!!.currentRegionDarkness().isDark
+        } else {
+            val isLightTheme = TypedValue()
+            context.theme.resolveAttribute(android.R.attr.isLightTheme, isLightTheme, true)
+            smallClockIsDark = isLightTheme.data == 0
+            largeClockIsDark = isLightTheme.data == 0
         }
+
+        clock?.smallClock?.events?.onRegionDarknessChanged(smallClockIsDark)
+        clock?.largeClock?.events?.onRegionDarknessChanged(largeClockIsDark)
     }
 
-    fun updateRegionSamplers(currentClock: Clock?) {
-        smallRegionSamplingInstance = createRegionSampler(
-                currentClock?.smallClock,
+    private fun updateRegionSamplers(currentClock: ClockController?) {
+        smallRegionSampler?.stopRegionSampler()
+        largeRegionSampler?.stopRegionSampler()
+
+        smallRegionSampler = createRegionSampler(
+                currentClock?.smallClock?.view,
                 mainExecutor,
                 bgExecutor,
                 regionSamplingEnabled,
-                updateFun
+                ::updateColors
         )
 
-        largeRegionSamplingInstance = createRegionSampler(
-                currentClock?.largeClock,
+        largeRegionSampler = createRegionSampler(
+                currentClock?.largeClock?.view,
                 mainExecutor,
                 bgExecutor,
                 regionSamplingEnabled,
-                updateFun
+                ::updateColors
         )
 
-        smallRegionSamplingInstance.startRegionSampler()
-        largeRegionSamplingInstance.startRegionSampler()
+        smallRegionSampler!!.startRegionSampler()
+        largeRegionSampler!!.startRegionSampler()
 
-        updateFun.updateColors()
+        updateColors()
     }
 
     protected open fun createRegionSampler(
@@ -117,25 +120,29 @@
             mainExecutor: Executor?,
             bgExecutor: Executor?,
             regionSamplingEnabled: Boolean,
-            updateFun: RegionSamplingInstance.UpdateColorCallback
+            updateColors: () -> Unit
     ): RegionSamplingInstance {
         return RegionSamplingInstance(
             sampledView,
             mainExecutor,
             bgExecutor,
             regionSamplingEnabled,
-            updateFun)
+            object : RegionSamplingInstance.UpdateColorCallback {
+                override fun updateColors() {
+                    updateColors()
+                }
+            })
     }
 
-    lateinit var smallRegionSamplingInstance: RegionSamplingInstance
-    lateinit var largeRegionSamplingInstance: RegionSamplingInstance
+    var smallRegionSampler: RegionSamplingInstance? = null
+    var largeRegionSampler: RegionSamplingInstance? = null
 
     private var smallClockIsDark = true
     private var largeClockIsDark = true
 
     private val configListener = object : ConfigurationController.ConfigurationListener {
         override fun onThemeChanged() {
-            updateFun.updateColors()
+            clock?.events?.onColorPaletteChanged(resources)
         }
 
         override fun onDensityOrFontScaleChanged() {
@@ -145,7 +152,7 @@
 
     private val batteryCallback = object : BatteryStateChangeCallback {
         override fun onBatteryLevelChanged(level: Int, pluggedIn: Boolean, charging: Boolean) {
-            if (isKeyguardShowing && !isCharging && charging) {
+            if (isKeyguardVisible && !isCharging && charging) {
                 clock?.animations?.charge()
             }
             isCharging = charging
@@ -168,9 +175,9 @@
     }
 
     private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
-        override fun onKeyguardVisibilityChanged(showing: Boolean) {
-            isKeyguardShowing = showing
-            if (!isKeyguardShowing) {
+        override fun onKeyguardVisibilityChanged(visible: Boolean) {
+            isKeyguardVisible = visible
+            if (!isKeyguardVisible) {
                 clock?.animations?.doze(if (isDozing) 1f else 0f)
             }
         }
@@ -204,8 +211,8 @@
         batteryController.addCallback(batteryCallback)
         keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
         statusBarStateController.addCallback(statusBarStateListener)
-        smallRegionSamplingInstance.startRegionSampler()
-        largeRegionSamplingInstance.startRegionSampler()
+        smallRegionSampler?.startRegionSampler()
+        largeRegionSampler?.startRegionSampler()
     }
 
     fun unregisterListeners() {
@@ -214,8 +221,8 @@
         batteryController.removeCallback(batteryCallback)
         keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
         statusBarStateController.removeCallback(statusBarStateListener)
-        smallRegionSamplingInstance.stopRegionSampler()
-        largeRegionSamplingInstance.stopRegionSampler()
+        smallRegionSampler?.stopRegionSampler()
+        largeRegionSampler?.stopRegionSampler()
     }
 
     /**
@@ -224,8 +231,8 @@
     fun dump(pw: PrintWriter) {
         pw.println(this)
         clock?.dump(pw)
-        smallRegionSamplingInstance.dump(pw)
-        largeRegionSamplingInstance.dump(pw)
+        smallRegionSampler?.dump(pw)
+        largeRegionSampler?.dump(pw)
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index d7cd1d0..d03ef98 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -17,7 +17,7 @@
 import com.android.keyguard.dagger.KeyguardStatusViewScope;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
-import com.android.systemui.plugins.Clock;
+import com.android.systemui.plugins.ClockController;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -94,7 +94,7 @@
         onDensityOrFontScaleChanged();
     }
 
-    void setClock(Clock clock, int statusBarState) {
+    void setClock(ClockController clock, int statusBarState) {
         // Disconnect from existing plugin.
         mSmallClockFrame.removeAllViews();
         mLargeClockFrame.removeAllViews();
@@ -105,11 +105,14 @@
         }
 
         // Attach small and big clock views to hierarchy.
-        mSmallClockFrame.addView(clock.getSmallClock());
-        mLargeClockFrame.addView(clock.getLargeClock());
+        Log.i(TAG, "Attached new clock views to switch");
+        mSmallClockFrame.addView(clock.getSmallClock().getView());
+        mLargeClockFrame.addView(clock.getLargeClock().getView());
     }
 
     private void updateClockViews(boolean useLargeClock, boolean animate) {
+        Log.i(TAG, "updateClockViews; useLargeClock=" + useLargeClock + "; animate=" + animate
+                + "; mChildrenAreLaidOut=" + mChildrenAreLaidOut);
         if (mClockInAnim != null) mClockInAnim.cancel();
         if (mClockOutAnim != null) mClockOutAnim.cancel();
         if (mStatusAreaAnim != null) mStatusAreaAnim.cancel();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 2165099..b450ec3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -40,7 +40,7 @@
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.plugins.Clock;
+import com.android.systemui.plugins.ClockController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.clocks.ClockRegistry;
 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
@@ -262,7 +262,7 @@
 
         mCurrentClockSize = clockSize;
 
-        Clock clock = getClock();
+        ClockController clock = getClock();
         boolean appeared = mView.switchToClock(clockSize, animate);
         if (clock != null && animate && appeared && clockSize == LARGE) {
             clock.getAnimations().enter();
@@ -273,7 +273,7 @@
      * Animates the clock view between folded and unfolded states
      */
     public void animateFoldToAod(float foldFraction) {
-        Clock clock = getClock();
+        ClockController clock = getClock();
         if (clock != null) {
             clock.getAnimations().fold(foldFraction);
         }
@@ -286,7 +286,7 @@
         if (mSmartspaceController != null) {
             mSmartspaceController.requestSmartspaceUpdate();
         }
-        Clock clock = getClock();
+        ClockController clock = getClock();
         if (clock != null) {
             clock.getEvents().onTimeTick();
         }
@@ -319,17 +319,17 @@
      * We can't directly getBottom() because clock changes positions in AOD for burn-in
      */
     int getClockBottom(int statusBarHeaderHeight) {
-        Clock clock = getClock();
+        ClockController clock = getClock();
         if (clock == null) {
             return 0;
         }
 
         if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
             int frameHeight = mLargeClockFrame.getHeight();
-            int clockHeight = clock.getLargeClock().getHeight();
+            int clockHeight = clock.getLargeClock().getView().getHeight();
             return frameHeight / 2 + clockHeight / 2;
         } else {
-            int clockHeight = clock.getSmallClock().getHeight();
+            int clockHeight = clock.getSmallClock().getView().getHeight();
             return clockHeight + statusBarHeaderHeight + mKeyguardClockTopMargin;
         }
     }
@@ -338,15 +338,15 @@
      * Get the height of the currently visible clock on the keyguard.
      */
     int getClockHeight() {
-        Clock clock = getClock();
+        ClockController clock = getClock();
         if (clock == null) {
             return 0;
         }
 
         if (mLargeClockFrame.getVisibility() == View.VISIBLE) {
-            return clock.getLargeClock().getHeight();
+            return clock.getLargeClock().getView().getHeight();
         } else {
-            return clock.getSmallClock().getHeight();
+            return clock.getSmallClock().getView().getHeight();
         }
     }
 
@@ -361,12 +361,12 @@
         mNotificationIconAreaController.setupAodIcons(nic);
     }
 
-    private void setClock(Clock clock) {
+    private void setClock(ClockController clock) {
         mClockEventController.setClock(clock);
         mView.setClock(clock, mStatusBarStateController.getState());
     }
 
-    private Clock getClock() {
+    private ClockController getClock() {
         return mClockEventController.getClock();
     }
 
@@ -398,7 +398,8 @@
     public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("currentClockSizeLarge=" + (mCurrentClockSize == LARGE));
         pw.println("mCanShowDoubleLineClock=" + mCanShowDoubleLineClock);
-        Clock clock = getClock();
+        mView.dump(pw, args);
+        ClockController clock = getClock();
         if (clock != null) {
             clock.dump(pw);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 453072b..5d86ccd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -176,6 +176,8 @@
 
     @Override
     public void startAppearAnimation() {
+        setAlpha(1f);
+        setTranslationY(0);
         if (mAppearAnimator.isRunning()) {
             mAppearAnimator.cancel();
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
index 1e5c53d..2cc5ccdc 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java
@@ -24,7 +24,6 @@
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
 
 import android.animation.Animator;
@@ -107,8 +106,6 @@
                 return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_password;
-            case PROMPT_REASON_TRUSTAGENT_EXPIRED:
-                return R.string.kg_prompt_reason_timeout_password;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 5b22324..9871645 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -330,9 +330,6 @@
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
                 mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
                 break;
-            case PROMPT_REASON_TRUSTAGENT_EXPIRED:
-                mMessageAreaController.setMessage(R.string.kg_prompt_reason_timeout_pattern);
-                break;
             case PROMPT_REASON_NONE:
                 break;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 0a91150..c46e33d 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -22,7 +22,6 @@
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_PREPARE_FOR_UPDATE;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_RESTART;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TIMEOUT;
-import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
 import static com.android.keyguard.KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
 
 import android.animation.Animator;
@@ -124,8 +123,6 @@
                 return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_pin;
-            case PROMPT_REASON_TRUSTAGENT_EXPIRED:
-                return R.string.kg_prompt_reason_timeout_pin;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index e7f44aa..c34db15 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -536,7 +536,7 @@
     }
 
     /**
-     * Runs after a succsssful authentication only
+     * Runs after a successful authentication only
      */
     public void startDisappearAnimation(SecurityMode securitySelection) {
         mDisappearAnimRunning = true;
@@ -895,6 +895,7 @@
                 mPopup.dismiss();
                 mPopup = null;
             }
+            setupUserSwitcher();
         }
 
         @Override
@@ -905,6 +906,11 @@
                         android.R.attr.textColorPrimary));
                 header.setBackground(mView.getContext().getDrawable(
                         R.drawable.bouncer_user_switcher_header_bg));
+                Drawable keyDownDrawable =
+                        ((LayerDrawable) header.getBackground().mutate()).findDrawableByLayerId(
+                                R.id.user_switcher_key_down);
+                keyDownDrawable.setTintList(Utils.getColorAttr(mView.getContext(),
+                        android.R.attr.textColorPrimary));
             }
         }
 
@@ -928,7 +934,6 @@
                 return;
             }
 
-            mView.setAlpha(1f);
             mUserSwitcherViewGroup.setAlpha(0f);
             ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(mUserSwitcherViewGroup, View.ALPHA,
                     1f);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 57058b7..d448f40 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -427,6 +427,7 @@
 
     public void startAppearAnimation() {
         if (mCurrentSecurityMode != SecurityMode.None) {
+            mView.setAlpha(1f);
             mView.startAppearAnimation(mCurrentSecurityMode);
             getCurrentSecurityController().startAppearAnimation();
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
index 9d0a8ac..ac00e94 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityView.java
@@ -61,12 +61,6 @@
     int PROMPT_REASON_NON_STRONG_BIOMETRIC_TIMEOUT = 7;
 
     /**
-     * Some auth is required because the trustagent expired either from timeout or manually by
-     * the user
-     */
-    int PROMPT_REASON_TRUSTAGENT_EXPIRED = 8;
-
-    /**
      * Reset the view and prepare to take input. This should do things like clearing the
      * password or pattern and clear error messages.
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index c715a4e..e9f06ed 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -212,9 +212,9 @@
         }
 
         @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            if (showing) {
-                if (DEBUG) Slog.v(TAG, "refresh statusview showing:" + showing);
+        public void onKeyguardVisibilityChanged(boolean visible) {
+            if (visible) {
+                if (DEBUG) Slog.v(TAG, "refresh statusview visible:true");
                 refreshTime();
             }
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index 7d6f377..f974e27 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -20,8 +20,8 @@
 import android.view.ViewGroup
 import com.android.systemui.R
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator
-import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.LEFT
-import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.RIGHT
+import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END
+import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
 import com.android.systemui.unfold.SysUIUnfoldScope
 import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
@@ -49,13 +49,14 @@
         UnfoldConstantTranslateAnimator(
             viewsIdToTranslate =
                 setOf(
-                    ViewIdToTranslate(R.id.keyguard_status_area, LEFT, filterNever),
-                    ViewIdToTranslate(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
-                    ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
+                    ViewIdToTranslate(R.id.keyguard_status_area, START, filterNever),
                     ViewIdToTranslate(
-                        R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
-                    ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
-                    ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
+                        R.id.lockscreen_clock_view_large, START, filterSplitShadeOnly),
+                    ViewIdToTranslate(R.id.lockscreen_clock_view, START, filterNever),
+                    ViewIdToTranslate(
+                        R.id.notification_stack_scroller, END, filterSplitShadeOnly),
+                    ViewIdToTranslate(R.id.start_button, START, filterNever),
+                    ViewIdToTranslate(R.id.end_button, END, filterNever)),
             progressProvider = unfoldProgressProvider)
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 6eef3b3..d58ba80 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -69,8 +69,7 @@
 
 import android.annotation.AnyThread;
 import android.annotation.MainThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.app.ActivityManager;
 import android.app.ActivityTaskManager;
 import android.app.ActivityTaskManager.RootTaskInfo;
@@ -113,7 +112,6 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
-import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.ServiceState;
@@ -126,6 +124,9 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.InstanceId;
@@ -281,9 +282,9 @@
     private final KeyguardUpdateMonitorLogger mLogger;
     private final boolean mIsPrimaryUser;
     private final AuthController mAuthController;
-    private final StatusBarStateController mStatusBarStateController;
     private final UiEventLogger mUiEventLogger;
     private final Set<Integer> mFaceAcquiredInfoIgnoreList;
+    private final PackageManager mPackageManager;
     private int mStatusBarState;
     private final StatusBarStateController.StateListener mStatusBarStateControllerListener =
             new StatusBarStateController.StateListener() {
@@ -304,10 +305,11 @@
     };
 
     HashMap<Integer, SimData> mSimDatas = new HashMap<>();
-    HashMap<Integer, ServiceState> mServiceStates = new HashMap<Integer, ServiceState>();
+    HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
 
     private int mPhoneState;
-    private boolean mKeyguardIsVisible;
+    private boolean mKeyguardShowing;
+    private boolean mKeyguardOccluded;
     private boolean mCredentialAttempted;
     private boolean mKeyguardGoingAway;
     private boolean mGoingToSleep;
@@ -317,7 +319,6 @@
     private boolean mAuthInterruptActive;
     private boolean mNeedsSlowUnlockTransition;
     private boolean mAssistantVisible;
-    private boolean mKeyguardOccluded;
     private boolean mOccludingAppRequestingFp;
     private boolean mOccludingAppRequestingFace;
     private boolean mSecureCameraLaunched;
@@ -336,34 +337,41 @@
     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
             mCallbacks = Lists.newArrayList();
     private ContentObserver mDeviceProvisionedObserver;
-    private ContentObserver mTimeFormatChangeObserver;
+    private final ContentObserver mTimeFormatChangeObserver;
 
     private boolean mSwitchingUser;
 
     private boolean mDeviceInteractive;
-    private SubscriptionManager mSubscriptionManager;
+    private final SubscriptionManager mSubscriptionManager;
     private final TelephonyListenerManager mTelephonyListenerManager;
-    private List<SubscriptionInfo> mSubscriptionInfo;
-    private TrustManager mTrustManager;
-    private UserManager mUserManager;
-    private KeyguardBypassController mKeyguardBypassController;
-    private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
-    private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
-    private LockPatternUtils mLockPatternUtils;
-    private final IDreamManager mDreamManager;
-    private boolean mIsDreaming;
+    private final TrustManager mTrustManager;
+    private final UserManager mUserManager;
     private final DevicePolicyManager mDevicePolicyManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final InteractionJankMonitor mInteractionJankMonitor;
     private final LatencyTracker mLatencyTracker;
+    private final StatusBarStateController mStatusBarStateController;
+    private final Executor mBackgroundExecutor;
+    private final SensorPrivacyManager mSensorPrivacyManager;
+    private final ActiveUnlockConfig mActiveUnlockConfig;
+    private final PowerManager mPowerManager;
+    private final IDreamManager mDreamManager;
+    private final TelephonyManager mTelephonyManager;
+    @Nullable
+    private final FingerprintManager mFpm;
+    @Nullable
+    private final FaceManager mFaceManager;
+    private final LockPatternUtils mLockPatternUtils;
+    private final boolean mWakeOnFingerprintAcquiredStart;
+
+    private KeyguardBypassController mKeyguardBypassController;
+    private List<SubscriptionInfo> mSubscriptionInfo;
+    private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+    private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+    private boolean mIsDreaming;
     private boolean mLogoutEnabled;
     private boolean mIsFaceEnrolled;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-    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
@@ -390,12 +398,10 @@
     }
     private final Handler mHandler;
 
-    private SparseBooleanArray mBiometricEnabledForUser = new SparseBooleanArray();
-    private BiometricManager mBiometricManager;
-    private IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
+    private final IBiometricEnabledOnKeyguardCallback mBiometricEnabledCallback =
             new IBiometricEnabledOnKeyguardCallback.Stub() {
                 @Override
-                public void onChanged(boolean enabled, int userId) throws RemoteException {
+                public void onChanged(boolean enabled, int userId) {
                     mHandler.post(() -> {
                         mBiometricEnabledForUser.put(userId, enabled);
                         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
@@ -414,7 +420,7 @@
         }
     };
 
-    private OnSubscriptionsChangedListener mSubscriptionListener =
+    private final OnSubscriptionsChangedListener mSubscriptionListener =
             new OnSubscriptionsChangedListener() {
                 @Override
                 public void onSubscriptionsChanged() {
@@ -433,11 +439,12 @@
         }
     }
 
-    private SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray();
-    private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
-    private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
-    private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
-    private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>();
+    private final SparseBooleanArray mUserIsUnlocked = new SparseBooleanArray();
+    private final SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
+    private final SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
+    private final SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray();
+    private final SparseBooleanArray mBiometricEnabledForUser = new SparseBooleanArray();
+    private final Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<>();
 
     @VisibleForTesting
     SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>();
@@ -598,7 +605,7 @@
         }
         if (sil == null) {
             // getCompleteActiveSubscriptionInfoList was null callers expect an empty list.
-            mSubscriptionInfo = new ArrayList<SubscriptionInfo>();
+            mSubscriptionInfo = new ArrayList<>();
         } else {
             mSubscriptionInfo = sil;
         }
@@ -613,7 +620,7 @@
      * of them based on carrier config. e.g. In this case we should only show one carrier name
      * on the status bar and quick settings.
      */
-    public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) {
+    public List<SubscriptionInfo> getFilteredSubscriptionInfo() {
         List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false);
         if (subscriptions.size() == 2) {
             SubscriptionInfo info1 = subscriptions.get(0);
@@ -674,14 +681,42 @@
     }
 
     /**
-     * Updates KeyguardUpdateMonitor's internal state to know if keyguard is occluded
+     * Updates KeyguardUpdateMonitor's internal state to know if keyguard is showing and if
+     * its occluded. The keyguard is considered visible if its showing and NOT occluded.
      */
-    public void setKeyguardOccluded(boolean occluded) {
-        mKeyguardOccluded = occluded;
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
-                FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED);
-    }
+    public void setKeyguardShowing(boolean showing, boolean occluded) {
+        final boolean occlusionChanged = mKeyguardOccluded != occluded;
+        final boolean showingChanged = mKeyguardShowing != showing;
+        if (!occlusionChanged && !showingChanged) {
+            return;
+        }
 
+        final boolean wasKeyguardVisible = isKeyguardVisible();
+        mKeyguardShowing = showing;
+        mKeyguardOccluded = occluded;
+        final boolean isKeyguardVisible = isKeyguardVisible();
+        mLogger.logKeyguardShowingChanged(showing, occluded, isKeyguardVisible);
+
+        if (isKeyguardVisible != wasKeyguardVisible) {
+            if (isKeyguardVisible) {
+                mSecureCameraLaunched = false;
+            }
+            for (int i = 0; i < mCallbacks.size(); i++) {
+                KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+                if (cb != null) {
+                    cb.onKeyguardVisibilityChanged(isKeyguardVisible);
+                }
+            }
+        }
+
+        if (occlusionChanged) {
+            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_UPDATED_KEYGUARD_OCCLUSION_CHANGED);
+        } else if (showingChanged) {
+            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                    FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED);
+        }
+    }
 
     /**
      * Request to listen for face authentication when an app is occluding keyguard.
@@ -733,7 +768,7 @@
      * If the device is dreaming, awakens the device
      */
     public void awakenFromDream() {
-        if (mIsDreaming && mDreamManager != null) {
+        if (mIsDreaming) {
             try {
                 mDreamManager.awaken();
             } catch (RemoteException e) {
@@ -778,12 +813,8 @@
     }
 
     private void reportSuccessfulBiometricUnlock(boolean isStrongBiometric, int userId) {
-        mBackgroundExecutor.execute(new Runnable() {
-            @Override
-            public void run() {
-                mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId);
-            }
-        });
+        mBackgroundExecutor.execute(
+                () -> mLockPatternUtils.reportSuccessfulBiometricUnlock(isStrongBiometric, userId));
     }
 
     private void handleFingerprintAuthFailed() {
@@ -866,7 +897,8 @@
         }
     }
 
-    private Runnable mRetryFingerprintAuthentication = new Runnable() {
+    private final Runnable mRetryFingerprintAuthentication = new Runnable() {
+        @SuppressLint("MissingPermission")
         @Override
         public void run() {
             mLogger.logRetryAfterFpHwUnavailable(mHardwareFingerprintUnavailableRetryCount);
@@ -910,7 +942,7 @@
 
         boolean lockedOutStateChanged = false;
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
-            lockedOutStateChanged |= !mFingerprintLockedOutPermanent;
+            lockedOutStateChanged = !mFingerprintLockedOutPermanent;
             mFingerprintLockedOutPermanent = true;
             mLogger.d("Fingerprint locked out - requiring strong auth");
             mLockPatternUtils.requireStrongAuth(
@@ -955,9 +987,9 @@
             // that the events will arrive in a particular order. Add a delay here in case
             // an unlock is in progress. In this is a normal unlock the extra delay won't
             // be noticeable.
-            mHandler.postDelayed(() -> {
-                updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
-            }, getBiometricLockoutDelay());
+            mHandler.postDelayed(
+                    () -> updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE),
+                    getBiometricLockoutDelay());
         } else {
             updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
         }
@@ -1091,7 +1123,7 @@
         }
     }
 
-    private Runnable mRetryFaceAuthentication = new Runnable() {
+    private final Runnable mRetryFaceAuthentication = new Runnable() {
         @Override
         public void run() {
             mLogger.logRetryingAfterFaceHwUnavailable(mHardwareFaceUnavailableRetryCount);
@@ -1117,12 +1149,8 @@
 
         // Error is always the end of authentication lifecycle
         mFaceCancelSignal = null;
-        boolean cameraPrivacyEnabled = false;
-        if (mSensorPrivacyManager != null) {
-            cameraPrivacyEnabled = mSensorPrivacyManager
-                    .isSensorPrivacyEnabled(SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE,
-                    SensorPrivacyManager.Sensors.CAMERA);
-        }
+        boolean cameraPrivacyEnabled = mSensorPrivacyManager.isSensorPrivacyEnabled(
+                SensorPrivacyManager.TOGGLE_TYPE_SOFTWARE, SensorPrivacyManager.Sensors.CAMERA);
 
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
@@ -1173,10 +1201,8 @@
         mFaceLockedOutPermanent = (mode == BIOMETRIC_LOCKOUT_PERMANENT);
         final boolean changed = (mFaceLockedOutPermanent != wasLockoutPermanent);
 
-        mHandler.postDelayed(() -> {
-            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
-                    FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET);
-        }, getBiometricLockoutDelay());
+        mHandler.postDelayed(() -> updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET), getBiometricLockoutDelay());
 
         if (changed) {
             notifyLockedOutStateChanged(BiometricSourceType.FACE);
@@ -1215,28 +1241,24 @@
         return mFaceRunningState == BIOMETRIC_STATE_RUNNING;
     }
 
-    private boolean isTrustDisabled(int userId) {
+    private boolean isTrustDisabled() {
         // Don't allow trust agent if device is secured with a SIM PIN. This is here
         // mainly because there's no other way to prompt the user to enter their SIM PIN
         // once they get past the keyguard screen.
-        final boolean disabledBySimPin = isSimPinSecure();
-        return disabledBySimPin;
+        return isSimPinSecure(); // Disabled by SIM PIN
     }
 
     private boolean isFingerprintDisabled(int userId) {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        return dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
-                & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0
+        return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, userId)
+                        & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0
                 || isSimPinSecure();
     }
 
     private boolean isFaceDisabled(int userId) {
-        final DevicePolicyManager dpm =
-                (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         // TODO(b/140035044)
-        return whitelistIpcs(() -> dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
-                & DevicePolicyManager.KEYGUARD_DISABLE_FACE) != 0
+        return whitelistIpcs(() ->
+                (mDevicePolicyManager.getKeyguardDisabledFeatures(null, userId)
+                        & DevicePolicyManager.KEYGUARD_DISABLE_FACE) != 0
                 || isSimPinSecure());
     }
 
@@ -1258,7 +1280,7 @@
     }
 
     public boolean getUserHasTrust(int userId) {
-        return !isTrustDisabled(userId) && mUserHasTrust.get(userId);
+        return !isTrustDisabled() && mUserHasTrust.get(userId);
     }
 
     /**
@@ -1290,7 +1312,7 @@
     }
 
     public boolean getUserTrustIsManaged(int userId) {
-        return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId);
+        return mUserTrustIsManaged.get(userId) && !isTrustDisabled();
     }
 
     private void updateSecondaryLockscreenRequirement(int userId) {
@@ -1308,7 +1330,7 @@
                 Intent intent =
                         new Intent(DevicePolicyManager.ACTION_BIND_SECONDARY_LOCKSCREEN_SERVICE)
                                 .setPackage(supervisorComponent.getPackageName());
-                ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent, 0);
+                ResolveInfo resolveInfo = mPackageManager.resolveService(intent, 0);
                 if (resolveInfo != null && resolveInfo.serviceInfo != null) {
                     Intent launchIntent =
                             new Intent().setComponent(resolveInfo.serviceInfo.getComponentName());
@@ -1677,22 +1699,19 @@
     CancellationSignal mFingerprintCancelSignal;
     @VisibleForTesting
     CancellationSignal mFaceCancelSignal;
-    private FingerprintManager mFpm;
-    private FaceManager mFaceManager;
     private List<FingerprintSensorPropertiesInternal> mFingerprintSensorProperties;
     private List<FaceSensorPropertiesInternal> mFaceSensorProperties;
     private boolean mFingerprintLockedOut;
     private boolean mFingerprintLockedOutPermanent;
     private boolean mFaceLockedOutPermanent;
-    private HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
-    private TelephonyManager mTelephonyManager;
+    private final HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
 
     /**
      * When we receive a
      * {@link com.android.internal.telephony.TelephonyIntents#ACTION_SIM_STATE_CHANGED} broadcast,
      * and then pass a result via our handler to {@link KeyguardUpdateMonitor#handleSimStateChange},
      * we need a single object to pass to the handler.  This class helps decode
-     * the intent and provide a {@link SimCard.State} result.
+     * the intent and provide a {@link SimData} result.
      */
     private static class SimData {
         public int simState;
@@ -1913,9 +1932,20 @@
             UiEventLogger uiEventLogger,
             // This has to be a provider because SessionTracker depends on KeyguardUpdateMonitor :(
             Provider<SessionTracker> sessionTrackerProvider,
-            PowerManager powerManager) {
+            PowerManager powerManager,
+            TrustManager trustManager,
+            SubscriptionManager subscriptionManager,
+            UserManager userManager,
+            IDreamManager dreamManager,
+            DevicePolicyManager devicePolicyManager,
+            SensorPrivacyManager sensorPrivacyManager,
+            TelephonyManager telephonyManager,
+            PackageManager packageManager,
+            @Nullable FaceManager faceManager,
+            @Nullable FingerprintManager fingerprintManager,
+            @Nullable BiometricManager biometricManager) {
         mContext = context;
-        mSubscriptionManager = SubscriptionManager.from(context);
+        mSubscriptionManager = subscriptionManager;
         mTelephonyListenerManager = telephonyListenerManager;
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
         mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged);
@@ -1929,12 +1959,20 @@
         mLockPatternUtils = lockPatternUtils;
         mAuthController = authController;
         dumpManager.registerDumpable(getClass().getName(), this);
-        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
+        mSensorPrivacyManager = sensorPrivacyManager;
         mActiveUnlockConfig = activeUnlockConfiguration;
         mLogger = logger;
         mUiEventLogger = uiEventLogger;
         mSessionTrackerProvider = sessionTrackerProvider;
         mPowerManager = powerManager;
+        mTrustManager = trustManager;
+        mUserManager = userManager;
+        mDreamManager = dreamManager;
+        mTelephonyManager = telephonyManager;
+        mDevicePolicyManager = devicePolicyManager;
+        mPackageManager = packageManager;
+        mFpm = fingerprintManager;
+        mFaceManager = faceManager;
         mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
         mWakeOnFingerprintAcquiredStart = context.getResources()
                         .getBoolean(com.android.internal.R.bool.kg_wake_on_acquire_start);
@@ -2079,8 +2117,7 @@
         // listener now with the service state from the default sub.
         mBackgroundExecutor.execute(() -> {
             int subId = SubscriptionManager.getDefaultSubscriptionId();
-            ServiceState serviceState = mContext.getSystemService(TelephonyManager.class)
-                    .getServiceStateForSubscriber(subId);
+            ServiceState serviceState = mTelephonyManager.getServiceStateForSubscriber(subId);
             mHandler.sendMessage(
                     mHandler.obtainMessage(MSG_SERVICE_STATE_CHANGE, subId, 0, serviceState));
         });
@@ -2102,26 +2139,21 @@
             e.rethrowAsRuntimeException();
         }
 
-        mTrustManager = context.getSystemService(TrustManager.class);
         mTrustManager.registerTrustListener(this);
 
         setStrongAuthTracker(mStrongAuthTracker);
 
-        mDreamManager = IDreamManager.Stub.asInterface(
-                ServiceManager.getService(DreamService.DREAM_SERVICE));
-
-        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
-            mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
+        if (mFpm != null) {
             mFingerprintSensorProperties = mFpm.getSensorPropertiesInternal();
+            mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
         }
-        if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
-            mFaceManager = (FaceManager) context.getSystemService(Context.FACE_SERVICE);
+        if (mFaceManager != null) {
             mFaceSensorProperties = mFaceManager.getSensorPropertiesInternal();
+            mFaceManager.addLockoutResetCallback(mFaceLockoutResetCallback);
         }
 
-        if (mFpm != null || mFaceManager != null) {
-            mBiometricManager = context.getSystemService(BiometricManager.class);
-            mBiometricManager.registerEnabledOnKeyguardCallback(mBiometricEnabledCallback);
+        if (biometricManager != null) {
+            biometricManager.registerEnabledOnKeyguardCallback(mBiometricEnabledCallback);
         }
 
         // in case authenticators aren't registered yet at this point:
@@ -2139,19 +2171,11 @@
             }
         });
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE, FACE_AUTH_UPDATED_ON_KEYGUARD_INIT);
-        if (mFpm != null) {
-            mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
-        }
-        if (mFaceManager != null) {
-            mFaceManager.addLockoutResetCallback(mFaceLockoutResetCallback);
-        }
 
         TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
-        mUserManager = context.getSystemService(UserManager.class);
         mIsPrimaryUser = mUserManager.isPrimaryUser();
         int user = ActivityManager.getCurrentUser();
         mUserIsUnlocked.put(user, mUserManager.isUserUnlocked(user));
-        mDevicePolicyManager = context.getSystemService(DevicePolicyManager.class);
         mLogoutEnabled = mDevicePolicyManager.isLogoutEnabled();
         updateSecondaryLockscreenRequirement(user);
         List<UserInfo> allUsers = mUserManager.getUsers();
@@ -2161,22 +2185,8 @@
         }
         updateAirplaneModeState();
 
-        mTelephonyManager =
-                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
-        if (mTelephonyManager != null) {
-            mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
-            // Set initial sim states values.
-            for (int slot = 0; slot < mTelephonyManager.getActiveModemCount(); slot++) {
-                int state = mTelephonyManager.getSimState(slot);
-                int[] subIds = mSubscriptionManager.getSubscriptionIds(slot);
-                if (subIds != null) {
-                    for (int subId : subIds) {
-                        mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, subId, slot, state)
-                                .sendToTarget();
-                    }
-                }
-            }
-        }
+        mTelephonyListenerManager.addActiveDataSubscriptionIdListener(mPhoneStateListener);
+        initializeSimState();
 
         mTimeFormatChangeObserver = new ContentObserver(mHandler) {
             @Override
@@ -2193,6 +2203,20 @@
                 false, mTimeFormatChangeObserver, UserHandle.USER_ALL);
     }
 
+    private void initializeSimState() {
+        // Set initial sim states values.
+        for (int slot = 0; slot < mTelephonyManager.getActiveModemCount(); slot++) {
+            int state = mTelephonyManager.getSimState(slot);
+            int[] subIds = mSubscriptionManager.getSubscriptionIds(slot);
+            if (subIds != null) {
+                for (int subId : subIds) {
+                    mHandler.obtainMessage(MSG_SIM_STATE_CHANGE, subId, slot, state)
+                            .sendToTarget();
+                }
+            }
+        }
+    }
+
     private void updateFaceEnrolled(int userId) {
         mIsFaceEnrolled = whitelistIpcs(
                 () -> mFaceManager != null && mFaceManager.isHardwareDetected()
@@ -2235,7 +2259,7 @@
         }
 
         @Override
-        public void onUserSwitchComplete(int newUserId) throws RemoteException {
+        public void onUserSwitchComplete(int newUserId) {
             mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCH_COMPLETE,
                     newUserId, 0));
         }
@@ -2323,7 +2347,7 @@
      */
     public void requestFaceAuth(boolean userInitiatedRequest,
             @FaceAuthApiRequestReason String reason) {
-        mLogger.logFaceAuthRequested(userInitiatedRequest);
+        mLogger.logFaceAuthRequested(userInitiatedRequest, reason);
         updateFaceListeningState(BIOMETRIC_ACTION_START, apiRequestReasonToUiEvent(reason));
     }
 
@@ -2446,7 +2470,7 @@
         // Triggers:
         final boolean triggerActiveUnlockForAssistant = shouldTriggerActiveUnlockForAssistant();
         final boolean awakeKeyguard = mBouncerFullyShown || mUdfpsBouncerShowing
-                || (mKeyguardIsVisible && !mGoingToSleep
+                || (isKeyguardVisible() && !mGoingToSleep
                 && mStatusBarState != StatusBarState.SHADE_LOCKED);
 
         // Gates:
@@ -2522,7 +2546,7 @@
         final boolean userDoesNotHaveTrust = !getUserHasTrust(user);
         final boolean shouldListenForFingerprintAssistant = shouldListenForFingerprintAssistant();
         final boolean shouldListenKeyguardState =
-                mKeyguardIsVisible
+                isKeyguardVisible()
                         || !mDeviceInteractive
                         || (mBouncerIsOrWillBeShowing && !mKeyguardGoingAway)
                         || mGoingToSleep
@@ -2571,7 +2595,7 @@
                     mFingerprintLockedOut,
                     mGoingToSleep,
                     mKeyguardGoingAway,
-                    mKeyguardIsVisible,
+                    isKeyguardVisible(),
                     mKeyguardOccluded,
                     mOccludingAppRequestingFp,
                     mIsPrimaryUser,
@@ -2593,7 +2617,7 @@
         }
 
         final boolean statusBarShadeLocked = mStatusBarState == StatusBarState.SHADE_LOCKED;
-        final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep
+        final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive
                 && !statusBarShadeLocked;
         final int user = getCurrentUser();
         final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
@@ -2639,7 +2663,7 @@
         // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
         // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
         final boolean shouldListen =
-                (mBouncerFullyShown && !mGoingToSleep
+                (mBouncerFullyShown
                         || mAuthInterruptActive
                         || mOccludingAppRequestingFace
                         || awakeKeyguard
@@ -2651,6 +2675,7 @@
                 && strongAuthAllowsScanning && mIsPrimaryUser
                 && (!mSecureCameraLaunched || mOccludingAppRequestingFace)
                 && !faceAuthenticated
+                && !mGoingToSleep
                 && !fpOrFaceIsLockedOut;
 
         // Aggregate relevant fields for debug logging.
@@ -2794,6 +2819,7 @@
         return isUnlockWithFacePossible(userId) || isUnlockWithFingerprintPossible(userId);
     }
 
+    @SuppressLint("MissingPermission")
     @VisibleForTesting
     boolean isUnlockWithFingerprintPossible(int userId) {
         // TODO (b/242022358), make this rely on onEnrollmentChanged event and update it only once.
@@ -2924,6 +2950,7 @@
         try {
             reply.sendResult(null);
         } catch (RemoteException e) {
+            mLogger.logException(e, "Ignored exception while userSwitching");
         }
     }
 
@@ -3147,32 +3174,18 @@
         callbacksRefreshCarrierInfo();
     }
 
+    /**
+     * Whether the keyguard is showing and not occluded.
+     */
     public boolean isKeyguardVisible() {
-        return mKeyguardIsVisible;
+        return isKeyguardShowing() && !mKeyguardOccluded;
     }
 
     /**
-     * Notifies that the visibility state of Keyguard has changed.
-     *
-     * <p>Needs to be called from the main thread.
+     * Whether the keyguard is showing. It may still be occluded and not visible.
      */
-    public void onKeyguardVisibilityChanged(boolean showing) {
-        Assert.isMainThread();
-        mLogger.logKeyguardVisibilityChanged(showing);
-        mKeyguardIsVisible = showing;
-
-        if (showing) {
-            mSecureCameraLaunched = false;
-        }
-
-        for (int i = 0; i < mCallbacks.size(); i++) {
-            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
-            if (cb != null) {
-                cb.onKeyguardVisibilityChangedRaw(showing);
-            }
-        }
-        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
-                FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED);
+    public boolean isKeyguardShowing() {
+        return mKeyguardShowing;
     }
 
     /**
@@ -3190,7 +3203,7 @@
             return false;
         }
         Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
-        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(homeIntent,
+        ResolveInfo resolveInfo = mPackageManager.resolveActivityAsUser(homeIntent,
                 0 /* flags */, getCurrentUser());
 
         if (resolveInfo == null) {
@@ -3320,11 +3333,7 @@
         }
 
         // change in battery overheat
-        if (current.health != old.health) {
-            return true;
-        }
-
-        return false;
+        return current.health != old.health;
     }
 
     /**
@@ -3375,10 +3384,8 @@
     public void setSwitchingUser(boolean switching) {
         mSwitchingUser = switching;
         // Since this comes in on a binder thread, we need to post if first
-        mHandler.post(() -> {
-            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
-                    FACE_AUTH_UPDATED_USER_SWITCHING);
-        });
+        mHandler.post(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
+                FACE_AUTH_UPDATED_USER_SWITCHING));
     }
 
     private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
@@ -3387,7 +3394,7 @@
         callback.onTimeChanged();
         callback.onPhoneStateChanged(mPhoneState);
         callback.onRefreshCarrierInfo();
-        callback.onKeyguardVisibilityChangedRaw(mKeyguardIsVisible);
+        callback.onKeyguardVisibilityChanged(isKeyguardVisible());
         callback.onTelephonyCapable(mTelephonyCapable);
 
         for (Entry<Integer, SimData> data : mSimDatas.entrySet()) {
@@ -3487,7 +3494,7 @@
     /**
      * If any SIM cards are currently secure.
      *
-     * @see #isSimPinSecure(State)
+     * @see #isSimPinSecure(int)
      */
     public boolean isSimPinSecure() {
         // True if any SIM is pin secure
@@ -3534,10 +3541,7 @@
      * @return true if and only if the state has changed for the specified {@code slotId}
      */
     private boolean refreshSimState(int subId, int slotId) {
-        final TelephonyManager tele =
-                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        int state = (tele != null) ?
-                tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
+        int state = mTelephonyManager.getSimState(slotId);
         SimData data = mSimDatas.get(subId);
         final boolean changed;
         if (data == null) {
@@ -3680,13 +3684,8 @@
      * Unregister all listeners.
      */
     public void destroy() {
-        // TODO: inject these dependencies:
-        TelephonyManager telephony =
-                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        if (telephony != null) {
-            mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
-        }
-
+        mStatusBarStateController.removeCallback(mStatusBarStateControllerListener);
+        mTelephonyListenerManager.removeActiveDataSubscriptionIdListener(mPhoneStateListener);
         mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionListener);
 
         if (mDeviceProvisionedObserver != null) {
@@ -3716,8 +3715,9 @@
         mHandler.removeCallbacksAndMessages(null);
     }
 
+    @SuppressLint("MissingPermission")
     @Override
-    public void dump(PrintWriter pw, String[] args) {
+    public void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
         pw.println("KeyguardUpdateMonitor state:");
         pw.println("  getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
         pw.println("  getUserUnlockedWithBiometric()="
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 7a42803..bc5ab88 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -16,7 +16,6 @@
 package com.android.keyguard;
 
 import android.hardware.biometrics.BiometricSourceType;
-import android.os.SystemClock;
 import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicyConstants;
 
@@ -32,10 +31,6 @@
  */
 public class KeyguardUpdateMonitorCallback {
 
-    private static final long VISIBILITY_CHANGED_COLLAPSE_MS = 1000;
-    private long mVisibilityChangedCalled;
-    private boolean mShowing;
-
     /**
      * Called when the battery status changes, e.g. when plugged in or unplugged, charge
      * level, etc. changes.
@@ -75,21 +70,6 @@
     public void onPhoneStateChanged(int phoneState) { }
 
     /**
-     * Called when the visibility of the keyguard changes.
-     * @param showing Indicates if the keyguard is now visible.
-     */
-    public void onKeyguardVisibilityChanged(boolean showing) { }
-
-    public void onKeyguardVisibilityChangedRaw(boolean showing) {
-        final long now = SystemClock.elapsedRealtime();
-        if (showing == mShowing
-                && (now - mVisibilityChangedCalled) < VISIBILITY_CHANGED_COLLAPSE_MS) return;
-        onKeyguardVisibilityChanged(showing);
-        mVisibilityChangedCalled = now;
-        mShowing = showing;
-    }
-
-    /**
      * Called when the keyguard enters or leaves bouncer mode.
      * @param bouncerIsOrWillBeShowing if true, keyguard is showing the bouncer or transitioning
      *                                 from/to bouncer mode.
@@ -97,6 +77,12 @@
     public void onKeyguardBouncerStateChanged(boolean bouncerIsOrWillBeShowing) { }
 
     /**
+     * Called when the keyguard visibility changes.
+     * @param visible whether the keyguard is showing and is NOT occluded
+     */
+    public void onKeyguardVisibilityChanged(boolean visible) { }
+
+    /**
      * Called when the keyguard fully transitions to the bouncer or is no longer the bouncer
      * @param bouncerIsFullyShowing if true, keyguard is fully showing the bouncer
      */
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
index efa5558..b793fd2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUserSwitcherPopupMenu.java
@@ -66,10 +66,13 @@
         listView.setDividerHeight(mContext.getResources().getDimensionPixelSize(
                 R.dimen.bouncer_user_switcher_popup_divider_height));
 
-        int height  = mContext.getResources().getDimensionPixelSize(
-                R.dimen.bouncer_user_switcher_popup_header_height);
-        listView.addHeaderView(createSpacer(height), null, false);
-        listView.addFooterView(createSpacer(height), null, false);
+        if (listView.getTag(R.id.header_footer_views_added_tag_key) == null) {
+            int height = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.bouncer_user_switcher_popup_header_height);
+            listView.addHeaderView(createSpacer(height), null, false);
+            listView.addFooterView(createSpacer(height), null, false);
+            listView.setTag(R.id.header_footer_views_added_tag_key, new Object());
+        }
 
         listView.setOnTouchListener((v, ev) -> {
             if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 2a36676..c41b752 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -447,14 +447,6 @@
     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    // reset mIsBouncerShowing state in case it was preemptively set
-                    // onLongPress
-                    mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
-                    updateVisibility();
-                }
-
-                @Override
                 public void onKeyguardBouncerStateChanged(boolean bouncer) {
                     mIsBouncerShowing = bouncer;
                     updateVisibility();
@@ -507,6 +499,11 @@
             // If biometrics were removed, local vars mCanDismissLockScreen and
             // mUserUnlockedWithBiometric may not be updated.
             mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
+
+            // reset mIsBouncerShowing state in case it was preemptively set
+            // onLongPress
+            mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
+
             updateKeyguardShowing();
             if (mIsKeyguardShowing) {
                 mUserUnlockedWithBiometric =
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.kt
new file mode 100644
index 0000000..50012a5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardLogger.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.keyguard.logging
+
+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.ERROR
+import com.android.systemui.log.LogLevel.VERBOSE
+import com.android.systemui.log.LogLevel.WARNING
+import com.android.systemui.log.MessageInitializer
+import com.android.systemui.log.MessagePrinter
+import com.android.systemui.log.dagger.KeyguardLog
+import com.google.errorprone.annotations.CompileTimeConstant
+import javax.inject.Inject
+
+private const val TAG = "KeyguardLog"
+
+/**
+ * Generic logger for keyguard that's wrapping [LogBuffer]. This class should be used for adding
+ * temporary logs or logs for smaller classes when creating whole new [LogBuffer] wrapper might be
+ * an overkill.
+ */
+class KeyguardLogger @Inject constructor(@KeyguardLog private val buffer: LogBuffer) {
+    fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG)
+
+    fun e(@CompileTimeConstant msg: String) = log(msg, ERROR)
+
+    fun v(@CompileTimeConstant msg: String) = log(msg, VERBOSE)
+
+    fun w(@CompileTimeConstant msg: String) = log(msg, WARNING)
+
+    fun log(msg: String, level: LogLevel) = buffer.log(TAG, level, msg)
+
+    private fun debugLog(messageInitializer: MessageInitializer, messagePrinter: MessagePrinter) {
+        buffer.log(TAG, DEBUG, messageInitializer, messagePrinter)
+    }
+
+    // TODO: remove after b/237743330 is fixed
+    fun logStatusBarCalculatedAlpha(alpha: Float) {
+        debugLog({ double1 = alpha.toDouble() }, { "Calculated new alpha: $double1" })
+    }
+
+    // TODO: remove after b/237743330 is fixed
+    fun logStatusBarExplicitAlpha(alpha: Float) {
+        debugLog({ double1 = alpha.toDouble() }, { "new mExplicitAlpha value: $double1" })
+    }
+
+    // TODO: remove after b/237743330 is fixed
+    fun logStatusBarAlphaVisibility(visibility: Int, alpha: Float, state: String) {
+        debugLog(
+            {
+                int1 = visibility
+                double1 = alpha.toDouble()
+                str1 = state
+            },
+            { "changing visibility to $int1 with alpha $double1 in state: $str1" }
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 7a00cd9..2eee957 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, ERROR)
+    fun v(@CompileTimeConstant msg: String) = log(msg, VERBOSE)
 
     fun w(@CompileTimeConstant msg: String) = log(msg, WARNING)
 
@@ -108,10 +108,11 @@
                 }, { "Face help received, msgId: $int1 msg: $str1" })
     }
 
-    fun logFaceAuthRequested(userInitiatedRequest: Boolean) {
-        logBuffer.log(TAG, DEBUG,
-                { bool1 = userInitiatedRequest },
-                { "requestFaceAuth() userInitiated=$bool1" })
+    fun logFaceAuthRequested(userInitiatedRequest: Boolean, reason: String) {
+        logBuffer.log(TAG, DEBUG, {
+            bool1 = userInitiatedRequest
+            str1 = reason
+        }, { "requestFaceAuth() userInitiated=$bool1 reason=$str1" })
     }
 
     fun logFaceAuthSuccess(userId: Int) {
@@ -170,8 +171,14 @@
         logBuffer.log(TAG, VERBOSE, { str1 = "$model" }, { str1!! })
     }
 
-    fun logKeyguardVisibilityChanged(showing: Boolean) {
-        logBuffer.log(TAG, DEBUG, { bool1 = showing }, { "onKeyguardVisibilityChanged($bool1)" })
+    fun logKeyguardShowingChanged(showing: Boolean, occluded: Boolean, visible: Boolean) {
+        logBuffer.log(TAG, DEBUG, {
+            bool1 = showing
+            bool2 = occluded
+            bool3 = visible
+        }, {
+            "keyguardShowingChanged(showing=$bool1 occluded=$bool2 visible=$bool3)"
+        })
     }
 
     fun logMissingSupervisorAppError(userId: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 67b683e..2e13903 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -455,6 +455,7 @@
                     }
                 }
 
+                boolean needToUpdateProviderViews = false;
                 final String newUniqueId = mDisplayInfo.uniqueId;
                 if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
                     mDisplayUniqueId = newUniqueId;
@@ -472,6 +473,37 @@
                         setupDecorations();
                         return;
                     }
+
+                    if (mScreenDecorHwcLayer != null) {
+                        updateHwLayerRoundedCornerDrawable();
+                        updateHwLayerRoundedCornerExistAndSize();
+                    }
+                    needToUpdateProviderViews = true;
+                }
+
+                final float newRatio = getPhysicalPixelDisplaySizeRatio();
+                if (mRoundedCornerResDelegate.getPhysicalPixelDisplaySizeRatio() != newRatio) {
+                    mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(newRatio);
+                    if (mScreenDecorHwcLayer != null) {
+                        updateHwLayerRoundedCornerExistAndSize();
+                    }
+                    needToUpdateProviderViews = true;
+                }
+
+                if (needToUpdateProviderViews) {
+                    updateOverlayProviderViews(null);
+                } else {
+                    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) {
+                    mScreenDecorHwcLayer.onDisplayChanged(newUniqueId);
                 }
             }
         };
@@ -1037,8 +1069,6 @@
                 && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) {
             mRotation = newRotation;
             mDisplayMode = newMod;
-            mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
-                    getPhysicalPixelDisplaySizeRatio());
             if (mScreenDecorHwcLayer != null) {
                 mScreenDecorHwcLayer.pendingConfigChange = false;
                 mScreenDecorHwcLayer.updateRotation(mRotation);
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index fe6dbe5..873a695 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -38,6 +38,8 @@
 import android.view.ViewConfiguration;
 import android.view.accessibility.AccessibilityEvent;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
@@ -66,7 +68,7 @@
     private static final int MAX_DISMISS_VELOCITY = 4000; // dp/sec
     private static final int SNAP_ANIM_LEN = SLOW_ANIMATIONS ? 1000 : 150; // ms
 
-    static final float SWIPE_PROGRESS_FADE_END = 0.5f; // fraction of thumbnail width
+    public static final float SWIPE_PROGRESS_FADE_END = 0.6f; // fraction of thumbnail width
                                               // beyond which swipe progress->0
     public static final float SWIPED_FAR_ENOUGH_SIZE_FRACTION = 0.6f;
     static final float MAX_SCROLL_SIZE_FRACTION = 0.3f;
@@ -235,7 +237,11 @@
         return Math.min(Math.max(mMinSwipeProgress, result), mMaxSwipeProgress);
     }
 
-    private float getSwipeAlpha(float progress) {
+    /**
+     * Returns the alpha value depending on the progress of the swipe.
+     */
+    @VisibleForTesting
+    public float getSwipeAlpha(float progress) {
         if (mFadeDependingOnAmountSwiped) {
             // The more progress has been fade, the lower the alpha value so that the view fades.
             return Math.max(1 - progress, 0);
@@ -260,7 +266,7 @@
                         animView.setLayerType(View.LAYER_TYPE_NONE, null);
                     }
                 }
-                animView.setAlpha(getSwipeAlpha(swipeProgress));
+                updateSwipeProgressAlpha(animView, getSwipeAlpha(swipeProgress));
             }
         }
         invalidateGlobalRegion(animView);
@@ -561,6 +567,14 @@
         mCallback.onChildSnappedBack(animView, targetLeft);
     }
 
+
+    /**
+     * Called to update the content alpha while the view is swiped
+     */
+    protected void updateSwipeProgressAlpha(View animView, float alpha) {
+        animView.setAlpha(alpha);
+    }
+
     /**
      * Give the swipe helper itself a chance to do something on snap back so NSSL doesn't have
      * to tell us what to do
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
index 50c38e5..a21f45f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIInitializer.java
@@ -97,7 +97,8 @@
                     .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
                     .setRecentTasks(mWMComponent.getRecentTasks())
                     .setBackAnimation(mWMComponent.getBackAnimation())
-                    .setFloatingTasks(mWMComponent.getFloatingTasks());
+                    .setFloatingTasks(mWMComponent.getFloatingTasks())
+                    .setDesktopMode(mWMComponent.getDesktopMode());
 
             // Only initialize when not starting from tests since this currently initializes some
             // components that shouldn't be run in the test environment
@@ -117,7 +118,8 @@
                     .setStartingSurface(Optional.ofNullable(null))
                     .setRecentTasks(Optional.ofNullable(null))
                     .setBackAnimation(Optional.ofNullable(null))
-                    .setFloatingTasks(Optional.ofNullable(null));
+                    .setFloatingTasks(Optional.ofNullable(null))
+                    .setDesktopMode(Optional.ofNullable(null));
         }
         mSysUIComponent = builder.build();
         if (initializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SimpleMirrorWindowControl.java b/packages/SystemUI/src/com/android/systemui/accessibility/SimpleMirrorWindowControl.java
index 2ba2bb6..ed6fbec 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SimpleMirrorWindowControl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SimpleMirrorWindowControl.java
@@ -45,7 +45,7 @@
     private boolean mShouldSetTouchStart;
 
     @Nullable private MoveWindowTask mMoveWindowTask;
-    private PointF mLastDrag = new PointF();
+    private final PointF mLastDrag = new PointF();
     private final Handler mHandler;
 
     SimpleMirrorWindowControl(Context context, Handler handler) {
@@ -92,8 +92,7 @@
     }
 
     private Point findOffset(View v, int moveFrameAmount) {
-        final Point offset = mTmpPoint;
-        offset.set(0, 0);
+        mTmpPoint.set(0, 0);
         if (v.getId() == R.id.left_control) {
             mTmpPoint.x = -moveFrameAmount;
         } else if (v.getId() == R.id.up_control) {
@@ -184,7 +183,7 @@
         private final int mYOffset;
         private final Handler mHandler;
         /** Time in milliseconds between successive task executions.*/
-        private long mPeriod;
+        private final long mPeriod;
         private boolean mCancel;
 
         MoveWindowTask(@NonNull MirrorWindowDelegate windowDelegate, Handler handler, int xOffset,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index ae73e34..8ded268 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -94,7 +94,7 @@
     private final Context mContext;
     private final Resources mResources;
     private final Handler mHandler;
-    private Rect mWindowBounds;
+    private final Rect mWindowBounds;
     private final int mDisplayId;
     @Surface.Rotation
     @VisibleForTesting
@@ -174,16 +174,16 @@
     private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
     private final MagnificationGestureDetector mGestureDetector;
     private final int mBounceEffectDuration;
-    private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
+    private final Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
     private Locale mLocale;
     private NumberFormat mPercentFormat;
     private float mBounceEffectAnimationScale;
-    private SysUiState mSysUiState;
+    private final SysUiState mSysUiState;
     // Set it to true when the view is overlapped with the gesture insets at the bottom.
     private boolean mOverlapWithGestureInsets;
 
     @Nullable
-    private MirrorWindowControl mMirrorWindowControl;
+    private final MirrorWindowControl mMirrorWindowControl;
 
     WindowMagnificationController(@UiContext Context context, @NonNull Handler handler,
             @NonNull WindowMagnificationAnimationController animationController,
@@ -489,9 +489,7 @@
     /** Returns the rotation degree change of two {@link Surface.Rotation} */
     private int getDegreeFromRotation(@Surface.Rotation int newRotation,
             @Surface.Rotation int oldRotation) {
-        final int rotationDiff = oldRotation - newRotation;
-        final int degree = (rotationDiff + 4) % 4 * 90;
-        return degree;
+        return (oldRotation - newRotation + 4) % 4 * 90;
     }
 
     private void createMirrorWindow() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index 11353f6..403941f 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -61,8 +61,8 @@
         }
 
         @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            mIsKeyguardVisible = showing;
+        public void onKeyguardVisibilityChanged(boolean visible) {
+            mIsKeyguardVisible = visible;
             handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 8f5cbb7..e74d810 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -849,7 +849,7 @@
         }
         mContainerState = STATE_GONE;
         if (isAttachedToWindow()) {
-            mWindowManager.removeView(this);
+            mWindowManager.removeViewImmediate(this);
         }
     }
 
@@ -875,6 +875,7 @@
     static WindowManager.LayoutParams getLayoutParams(IBinder windowToken, CharSequence title) {
         final int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                 | WindowManager.LayoutParams.FLAG_SECURE
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                 | WindowManager.LayoutParams.FLAG_DIM_BEHIND;
         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 4fee083..4363b88 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -117,7 +117,7 @@
     }
 
     fun showUnlockRipple(biometricSourceType: BiometricSourceType?) {
-        if (!(keyguardUpdateMonitor.isKeyguardVisible || keyguardUpdateMonitor.isDreaming) ||
+        if (!keyguardStateController.isShowing ||
             keyguardUpdateMonitor.userNeedsStrongAuth()) {
             return
         }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 27e9af9..412dc05 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -912,6 +912,12 @@
         if (view.isDisplayConfigured()) {
             view.unconfigureDisplay();
         }
+
+        if (mCancelAodTimeoutAction != null) {
+            mCancelAodTimeoutAction.run();
+            mCancelAodTimeoutAction = null;
+        }
+        mIsAodInterruptActive = false;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt b/packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt
index ca36375..379c819 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/ActionReceiver.kt
@@ -52,7 +52,7 @@
     private val userId: Int,
     private val registerAction: BroadcastReceiver.(IntentFilter) -> Unit,
     private val unregisterAction: BroadcastReceiver.() -> Unit,
-    private val bgExecutor: Executor,
+    private val workerExecutor: Executor,
     private val logger: BroadcastDispatcherLogger,
     private val testPendingRemovalAction: (BroadcastReceiver, Int) -> Boolean
 ) : BroadcastReceiver(), Dumpable {
@@ -112,7 +112,7 @@
         val id = index.getAndIncrement()
         logger.logBroadcastReceived(id, userId, intent)
         // Immediately return control to ActivityManager
-        bgExecutor.execute {
+        workerExecutor.execute {
             receiverDatas.forEach {
                 if (it.filter.matchCategories(intent.categories) == null &&
                     !testPendingRemovalAction(it.receiver, userId)) {
@@ -138,4 +138,4 @@
             println("Categories: ${activeCategories.joinToString(", ")}")
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index eb8cb47..537cbc5 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -34,7 +34,8 @@
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.BroadcastRunning
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.settings.UserTracker
 import java.io.PrintWriter
@@ -55,7 +56,6 @@
 private const val MSG_REMOVE_RECEIVER = 1
 private const val MSG_REMOVE_RECEIVER_FOR_USER = 2
 private const val TAG = "BroadcastDispatcher"
-private const val DEBUG = true
 
 /**
  * SystemUI master Broadcast Dispatcher.
@@ -73,15 +73,16 @@
 @SysUISingleton
 open class BroadcastDispatcher @Inject constructor(
     private val context: Context,
-    @Background private val bgLooper: Looper,
-    @Background private val bgExecutor: Executor,
+    @Main private val mainExecutor: Executor,
+    @BroadcastRunning private val broadcastLooper: Looper,
+    @BroadcastRunning private val broadcastExecutor: Executor,
     private val dumpManager: DumpManager,
     private val logger: BroadcastDispatcherLogger,
     private val userTracker: UserTracker,
     private val removalPendingStore: PendingRemovalStore
 ) : Dumpable {
 
-    // Only modify in BG thread
+    // Only modify in BroadcastRunning thread
     private val receiversByUser = SparseArray<UserBroadcastDispatcher>(20)
 
     fun initialize() {
@@ -148,7 +149,7 @@
         val data = ReceiverData(
                 receiver,
                 filter,
-                executor ?: context.mainExecutor,
+                executor ?: mainExecutor,
                 user ?: context.user,
                 permission
             )
@@ -181,7 +182,7 @@
         registerReceiver(
             receiver,
             filter,
-            bgExecutor,
+            broadcastExecutor,
             user,
             flags,
             permission,
@@ -246,8 +247,8 @@
             UserBroadcastDispatcher(
                 context,
                 userId,
-                bgLooper,
-                bgExecutor,
+                broadcastLooper,
+                broadcastExecutor,
                 logger,
                 removalPendingStore
             )
@@ -265,7 +266,7 @@
         ipw.decreaseIndent()
     }
 
-    private val handler = object : Handler(bgLooper) {
+    private val handler = object : Handler(broadcastLooper) {
 
         override fun handleMessage(msg: Message) {
             when (msg.what) {
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
index 6b15188..22dc94a 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.broadcast
 
+import android.annotation.SuppressLint
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.os.Handler
@@ -46,8 +47,8 @@
 open class UserBroadcastDispatcher(
     private val context: Context,
     private val userId: Int,
-    private val bgLooper: Looper,
-    private val bgExecutor: Executor,
+    private val workerLooper: Looper,
+    private val workerExecutor: Executor,
     private val logger: BroadcastDispatcherLogger,
     private val removalPendingStore: PendingRemovalStore
 ) : Dumpable {
@@ -66,9 +67,11 @@
         val permission: String?
     )
 
-    private val bgHandler = Handler(bgLooper)
+    private val wrongThreadErrorMsg = "This method should only be called from the worker thread " +
+            "(which is expected to be the BroadcastRunning thread)"
+    private val workerHandler = Handler(workerLooper)
 
-    // Only modify in BG thread
+    // Only modify in BroadcastRunning thread
     @VisibleForTesting
     internal val actionsToActionsReceivers = ArrayMap<ReceiverProperties, ActionReceiver>()
     private val receiverToActions = ArrayMap<BroadcastReceiver, MutableSet<String>>()
@@ -97,8 +100,7 @@
     }
 
     private fun handleRegisterReceiver(receiverData: ReceiverData, flags: Int) {
-        Preconditions.checkState(bgLooper.isCurrentThread,
-                "This method should only be called from BG thread")
+        Preconditions.checkState(workerLooper.isCurrentThread, wrongThreadErrorMsg)
         if (DEBUG) Log.w(TAG, "Register receiver: ${receiverData.receiver}")
         receiverToActions
                 .getOrPut(receiverData.receiver, { ArraySet() })
@@ -113,6 +115,7 @@
         logger.logReceiverRegistered(userId, receiverData.receiver, flags)
     }
 
+    @SuppressLint("RegisterReceiverViaContextDetector")
     @VisibleForTesting
     internal open fun createActionReceiver(
         action: String,
@@ -128,7 +131,7 @@
                             UserHandle.of(userId),
                             it,
                             permission,
-                            bgHandler,
+                            workerHandler,
                             flags
                     )
                     logger.logContextReceiverRegistered(userId, flags, it)
@@ -143,15 +146,14 @@
                                 IllegalStateException(e))
                     }
                 },
-                bgExecutor,
+                workerExecutor,
                 logger,
                 removalPendingStore::isPendingRemoval
         )
     }
 
     private fun handleUnregisterReceiver(receiver: BroadcastReceiver) {
-        Preconditions.checkState(bgLooper.isCurrentThread,
-                "This method should only be called from BG thread")
+        Preconditions.checkState(workerLooper.isCurrentThread, wrongThreadErrorMsg)
         if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver")
         receiverToActions.getOrDefault(receiver, mutableSetOf()).forEach {
             actionsToActionsReceivers.forEach { (key, value) ->
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index c292296..701df89 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -45,6 +45,7 @@
     public static final int QS_SWIPE_SIDE = 15;
     public static final int BACK_GESTURE = 16;
     public static final int QS_SWIPE_NESTED = 17;
+    public static final int MEDIA_SEEKBAR = 18;
 
     @IntDef({
             QUICK_SETTINGS,
@@ -65,7 +66,8 @@
             LOCK_ICON,
             QS_SWIPE_SIDE,
             QS_SWIPE_NESTED,
-            BACK_GESTURE
+            BACK_GESTURE,
+            MEDIA_SEEKBAR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InteractionType {}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
index 5e4f149..f8ee49a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceClassifier.java
@@ -23,6 +23,7 @@
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_FLING_THRESHOLD_IN;
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_DISTANCE_VERTICAL_SWIPE_THRESHOLD_IN;
 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QS_SWIPE_NESTED;
 import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
@@ -153,6 +154,7 @@
             @Classifier.InteractionType int interactionType,
             double historyBelief, double historyConfidence) {
         if (interactionType == BRIGHTNESS_SLIDER
+                || interactionType == MEDIA_SEEKBAR
                 || interactionType == SHADE_DRAG
                 || interactionType == QS_COLLAPSE
                 || interactionType == Classifier.UDFPS_AUTHENTICATION
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
index 07f94e7..e8c83b1 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -18,6 +18,7 @@
 
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_PROXIMITY_PERCENT_COVERED_THRESHOLD;
 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
 import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
 import static com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE;
 import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
@@ -119,7 +120,8 @@
             @Classifier.InteractionType int interactionType,
             double historyBelief, double historyConfidence) {
         if (interactionType == QUICK_SETTINGS || interactionType == BRIGHTNESS_SLIDER
-                || interactionType == QS_COLLAPSE || interactionType == QS_SWIPE_SIDE) {
+                || interactionType == QS_COLLAPSE || interactionType == QS_SWIPE_SIDE
+                || interactionType == MEDIA_SEEKBAR) {
             return Result.passed(0);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
index 776bc88..f576a5a 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/TypeClassifier.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
 import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
+import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
 import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
 import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
 import static com.android.systemui.classifier.Classifier.PULSE_EXPAND;
@@ -93,6 +94,10 @@
             case QS_SWIPE_NESTED:
                 wrongDirection = !vertical;
                 break;
+            case MEDIA_SEEKBAR:
+                confidence = 0;
+                wrongDirection = vertical;
+                break;
             default:
                 wrongDirection = true;
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index de2bdf7..840982c 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -22,6 +22,7 @@
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
 import static com.android.systemui.classifier.Classifier.LOCK_ICON;
+import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
 import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
 
 import android.graphics.Point;
@@ -91,6 +92,7 @@
             @Classifier.InteractionType int interactionType,
             double historyBelief, double historyConfidence) {
         if (interactionType == BRIGHTNESS_SLIDER
+                || interactionType == MEDIA_SEEKBAR
                 || interactionType == SHADE_DRAG
                 || interactionType == LOCK_ICON) {
             return Result.passed(0);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
index 3d5e601..e342ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
@@ -47,7 +47,8 @@
             shareIntent.putExtra(Intent.EXTRA_STREAM, clipData.getItemAt(0).getUri());
             shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         } else {
-            shareIntent.putExtra(Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context));
+            shareIntent.putExtra(
+                    Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString());
             shareIntent.setType("text/plain");
         }
         Intent chooserIntent = Intent.createChooser(shareIntent, null)
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.kt
new file mode 100644
index 0000000..f95a8ee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/view/LaunchableImageView.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.common.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.ImageView
+import com.android.systemui.animation.LaunchableView
+import com.android.systemui.animation.LaunchableViewDelegate
+
+class LaunchableImageView : ImageView, LaunchableView {
+    private val delegate =
+        LaunchableViewDelegate(
+            this,
+            superSetVisibility = { super.setVisibility(it) },
+            superSetTransitionVisibility = { super.setTransitionVisibility(it) },
+        )
+
+    constructor(context: Context?) : super(context)
+    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+    constructor(
+        context: Context?,
+        attrs: AttributeSet?,
+        defStyleAttr: Int,
+    ) : super(context, attrs, defStyleAttr)
+
+    constructor(
+        context: Context?,
+        attrs: AttributeSet?,
+        defStyleAttr: Int,
+        defStyleRes: Int,
+    ) : super(context, attrs, defStyleAttr, defStyleRes)
+
+    override fun setShouldBlockVisibilityChanges(block: Boolean) {
+        delegate.setShouldBlockVisibilityChanges(block)
+    }
+
+    override fun setVisibility(visibility: Int) {
+        delegate.setVisibility(visibility)
+    }
+
+    override fun setTransitionVisibility(visibility: Int) {
+        delegate.setTransitionVisibility(visibility)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/containeddrawable/ContainedDrawable.kt b/packages/SystemUI/src/com/android/systemui/containeddrawable/ContainedDrawable.kt
deleted file mode 100644
index d6a059d..0000000
--- a/packages/SystemUI/src/com/android/systemui/containeddrawable/ContainedDrawable.kt
+++ /dev/null
@@ -1,27 +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.containeddrawable
-
-import android.graphics.drawable.Drawable
-import androidx.annotation.DrawableRes
-
-/** Convenience container for [Drawable] or a way to load it later. */
-sealed class ContainedDrawable {
-    data class WithDrawable(val drawable: Drawable) : ContainedDrawable()
-    data class WithResource(@DrawableRes val resourceId: Int) : ContainedDrawable()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 4096ed4..139a8b7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -46,6 +46,7 @@
 import android.content.res.Resources;
 import android.hardware.SensorManager;
 import android.hardware.SensorPrivacyManager;
+import android.hardware.biometrics.BiometricManager;
 import android.hardware.camera2.CameraManager;
 import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.display.AmbientDisplayConfiguration;
@@ -237,22 +238,39 @@
     @Singleton
     static IDreamManager provideIDreamManager() {
         return IDreamManager.Stub.asInterface(
-                ServiceManager.checkService(DreamService.DREAM_SERVICE));
+                ServiceManager.getService(DreamService.DREAM_SERVICE));
     }
 
     @Provides
     @Singleton
     @Nullable
     static FaceManager provideFaceManager(Context context) {
-        return context.getSystemService(FaceManager.class);
-
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
+            return context.getSystemService(FaceManager.class);
+        }
+        return null;
     }
 
     @Provides
     @Singleton
     @Nullable
     static FingerprintManager providesFingerprintManager(Context context) {
-        return context.getSystemService(FingerprintManager.class);
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+            return context.getSystemService(FingerprintManager.class);
+        }
+        return null;
+    }
+
+    /**
+     * @return null if both faceManager and fingerprintManager are null.
+     */
+    @Provides
+    @Singleton
+    @Nullable
+    static BiometricManager providesBiometricManager(Context context,
+            @Nullable FaceManager faceManager, @Nullable FingerprintManager fingerprintManager) {
+        return faceManager == null && fingerprintManager == null ? null :
+                context.getSystemService(BiometricManager.class);
     }
 
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index a996699..48bef97 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -22,25 +22,19 @@
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
-import android.os.PowerManager;
 
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardViewController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.media.dagger.MediaModule;
 import com.android.systemui.navigationbar.gestural.GestureModule;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.qs.dagger.QSModule;
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
@@ -62,8 +56,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
+import com.android.systemui.statusbar.policy.AospPolicyModule;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -97,6 +90,7 @@
  * SystemUI code that variants of SystemUI _must_ include to function correctly.
  */
 @Module(includes = {
+        AospPolicyModule.class,
         GestureModule.class,
         MediaModule.class,
         PowerModule.class,
@@ -121,30 +115,6 @@
 
     @Provides
     @SysUISingleton
-    static BatteryController provideBatteryController(
-            Context context,
-            EnhancedEstimates enhancedEstimates,
-            PowerManager powerManager,
-            BroadcastDispatcher broadcastDispatcher,
-            DemoModeController demoModeController,
-            DumpManager dumpManager,
-            @Main Handler mainHandler,
-            @Background Handler bgHandler) {
-        BatteryController bC = new BatteryControllerImpl(
-                context,
-                enhancedEstimates,
-                powerManager,
-                broadcastDispatcher,
-                demoModeController,
-                dumpManager,
-                mainHandler,
-                bgHandler);
-        bC.init();
-        return bC;
-    }
-
-    @Provides
-    @SysUISingleton
     static SensorPrivacyController provideSensorPrivacyController(
             SensorPrivacyManager sensorPrivacyManager) {
         SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 7e30431..c2dffe8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -27,9 +27,6 @@
 import com.android.systemui.keyguard.KeyguardSliceProvider;
 import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli;
 import com.android.systemui.media.nearby.NearbyMediaDevicesManager;
-import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper;
-import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver;
-import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender;
 import com.android.systemui.people.PeopleProvider;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.unfold.FoldStateLogger;
@@ -40,6 +37,7 @@
 import com.android.wm.shell.TaskViewFactory;
 import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.bubbles.Bubbles;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
 import com.android.wm.shell.floating.FloatingTasks;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -113,6 +111,9 @@
         @BindsInstance
         Builder setFloatingTasks(Optional<FloatingTasks> f);
 
+        @BindsInstance
+        Builder setDesktopMode(Optional<DesktopMode> d);
+
         SysUIComponent build();
     }
 
@@ -129,9 +130,6 @@
         });
         getNaturalRotationUnfoldProgressProvider().ifPresent(o -> o.init());
         // No init method needed, just needs to be gotten so that it's created.
-        getMediaTttChipControllerSender();
-        getMediaTttChipControllerReceiver();
-        getMediaTttCommandLineHelper();
         getMediaMuteAwaitConnectionCli();
         getNearbyMediaDevicesManager();
         getUnfoldLatencyTracker().init();
@@ -202,15 +200,6 @@
     Optional<NaturalRotationUnfoldProgressProvider> getNaturalRotationUnfoldProgressProvider();
 
     /** */
-    Optional<MediaTttChipControllerSender> getMediaTttChipControllerSender();
-
-    /** */
-    Optional<MediaTttChipControllerReceiver> getMediaTttChipControllerReceiver();
-
-    /** */
-    Optional<MediaTttCommandLineHelper> getMediaTttCommandLineHelper();
-
-    /** */
     Optional<MediaMuteAwaitConnectionCli> getMediaMuteAwaitConnectionCli();
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 8bb27a7..55eda0a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -32,6 +32,9 @@
 import com.android.systemui.keyguard.KeyguardViewMediator
 import com.android.systemui.log.SessionTracker
 import com.android.systemui.media.RingtonePlayer
+import com.android.systemui.media.taptotransfer.MediaTttCommandLineHelper
+import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.sender.MediaTttChipControllerSender
 import com.android.systemui.power.PowerUI
 import com.android.systemui.recents.Recents
 import com.android.systemui.settings.dagger.MultiUserUtilsModule
@@ -213,4 +216,26 @@
     @IntoMap
     @ClassKey(KeyguardLiftController::class)
     abstract fun bindKeyguardLiftController(sysui: KeyguardLiftController): CoreStartable
+
+    /** Inject into MediaTttChipControllerReceiver. */
+    @Binds
+    @IntoMap
+    @ClassKey(MediaTttChipControllerReceiver::class)
+    abstract fun bindMediaTttChipControllerReceiver(
+            sysui: MediaTttChipControllerReceiver
+    ): CoreStartable
+
+    /** Inject into MediaTttChipControllerSender. */
+    @Binds
+    @IntoMap
+    @ClassKey(MediaTttChipControllerSender::class)
+    abstract fun bindMediaTttChipControllerSender(
+            sysui: MediaTttChipControllerSender
+    ): CoreStartable
+
+    /** Inject into MediaTttCommandLineHelper. */
+    @Binds
+    @IntoMap
+    @ClassKey(MediaTttCommandLineHelper::class)
+    abstract fun bindMediaTttCommandLineHelper(sysui: MediaTttCommandLineHelper): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 443d277..d70b971 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -43,7 +43,7 @@
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.data.BouncerViewModule;
 import com.android.systemui.log.dagger.LogModule;
-import com.android.systemui.media.dagger.MediaProjectionModule;
+import com.android.systemui.mediaprojection.appselector.MediaProjectionModule;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarComponent;
 import com.android.systemui.people.PeopleModule;
@@ -81,6 +81,7 @@
 import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
 import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
 import com.android.systemui.statusbar.window.StatusBarWindowModule;
+import com.android.systemui.telephony.data.repository.TelephonyRepositoryModule;
 import com.android.systemui.tuner.dagger.TunerModule;
 import com.android.systemui.unfold.SysUIUnfoldModule;
 import com.android.systemui.user.UserModule;
@@ -145,6 +146,7 @@
             StatusBarWindowModule.class,
             SysUIConcurrencyModule.class,
             SysUIUnfoldModule.class,
+            TelephonyRepositoryModule.class,
             TunerModule.class,
             UserModule.class,
             UtilModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index dd11549..096f969 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -30,6 +30,7 @@
 import com.android.wm.shell.dagger.TvWMShellModule;
 import com.android.wm.shell.dagger.WMShellModule;
 import com.android.wm.shell.dagger.WMSingleton;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
 import com.android.wm.shell.floating.FloatingTasks;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -112,4 +113,10 @@
 
     @WMSingleton
     Optional<FloatingTasks> getFloatingTasks();
+
+    /**
+     * Optional {@link DesktopMode} component for interacting with desktop mode.
+     */
+    @WMSingleton
+    Optional<DesktopMode> getDesktopMode();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BroadcastRunning.java
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BroadcastRunning.java
index 44c0496..5f8e540 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/qualifiers/BroadcastRunning.java
@@ -14,14 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.systemui.dagger.qualifiers;
 
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface BroadcastRunning {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
index 8b4aeef..a252864 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -78,18 +78,23 @@
         reloadMeasures()
     }
 
+    private fun reloadAll(newReloadToken: Int) {
+        if (reloadToken == newReloadToken) {
+            return
+        }
+        reloadToken = newReloadToken
+        reloadRes()
+        reloadMeasures()
+    }
+
     fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
         if (displayUniqueId != newDisplayUniqueId) {
             displayUniqueId = newDisplayUniqueId
             newReloadToken ?.let { reloadToken = it }
             reloadRes()
             reloadMeasures()
-        } else if (newReloadToken != null) {
-            if (reloadToken == newReloadToken) {
-                return
-            }
-            reloadToken = newReloadToken
-            reloadMeasures()
+        } else {
+            newReloadToken?.let { reloadAll(it) }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index b598554..4c4aa5c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -33,6 +33,18 @@
     boolean isProvisioned();
 
     /**
+     * Whether there's a pulse that's been requested but hasn't started transitioning to pulsing
+     * states yet.
+     */
+    boolean isPulsePending();
+
+    /**
+     * @param isPulsePending whether a pulse has been requested but hasn't started transitioning
+     *                       to the pulse state yet
+     */
+    void setPulsePending(boolean isPulsePending);
+
+    /**
      * Makes a current pulse last for twice as long.
      * @param reason why we're extending it.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 4161cf6..2e51b51 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -280,8 +280,8 @@
     /**
      * Appends pulse dropped event to logs
      */
-    public void tracePulseDropped(boolean pulsePending, DozeMachine.State state, boolean blocked) {
-        mLogger.logPulseDropped(pulsePending, state, blocked);
+    public void tracePulseDropped(String from, DozeMachine.State state) {
+        mLogger.logPulseDropped(from, state);
     }
 
     /**
@@ -292,6 +292,13 @@
     }
 
     /**
+     * Appends pulsing event to logs.
+     */
+    public void tracePulseEvent(String pulseEvent, boolean dozing, int pulseReason) {
+        mLogger.logPulseEvent(pulseEvent, dozing, DozeLog.reasonToString(pulseReason));
+    }
+
+    /**
      * Appends pulse dropped event to logs
      * @param reason why the pulse was dropped
      */
@@ -424,8 +431,8 @@
         }
 
         @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
-            traceKeyguard(showing);
+        public void onKeyguardVisibilityChanged(boolean visible) {
+            traceKeyguard(visible);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 4b279ec..cc57662 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -155,11 +155,11 @@
         })
     }
 
-    fun logKeyguardVisibilityChange(isShowing: Boolean) {
+    fun logKeyguardVisibilityChange(isVisible: Boolean) {
         buffer.log(TAG, INFO, {
-            bool1 = isShowing
+            bool1 = isVisible
         }, {
-            "Keyguard visibility change, isShowing=$bool1"
+            "Keyguard visibility change, isVisible=$bool1"
         })
     }
 
@@ -224,13 +224,12 @@
         })
     }
 
-    fun logPulseDropped(pulsePending: Boolean, state: DozeMachine.State, blocked: Boolean) {
+    fun logPulseDropped(from: String, state: DozeMachine.State) {
         buffer.log(TAG, INFO, {
-            bool1 = pulsePending
-            str1 = state.name
-            bool2 = blocked
+            str1 = from
+            str2 = state.name
         }, {
-            "Pulse dropped, pulsePending=$bool1 state=$str1 blocked=$bool2"
+            "Pulse dropped, cannot pulse from=$str1 state=$str2"
         })
     }
 
@@ -243,6 +242,16 @@
         })
     }
 
+    fun logPulseEvent(pulseEvent: String, dozing: Boolean, pulseReason: String) {
+        buffer.log(TAG, DEBUG, {
+            str1 = pulseEvent
+            bool1 = dozing
+            str2 = pulseReason
+        }, {
+            "Pulse-$str1 dozing=$bool1 pulseReason=$str2"
+        })
+    }
+
     fun logPulseDropped(reason: String) {
         buffer.log(TAG, INFO, {
             str1 = reason
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 00ac8bc..ef454ff 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -102,7 +102,6 @@
     private final UiEventLogger mUiEventLogger;
 
     private long mNotificationPulseTime;
-    private boolean mPulsePending;
     private Runnable mAodInterruptRunnable;
 
     /** see {@link #onProximityFar} prox for callback */
@@ -303,8 +302,8 @@
                         null /* onPulseSuppressedListener */);
             }
         } else {
-            proximityCheckThenCall((result) -> {
-                if (result != null && result) {
+            proximityCheckThenCall((isNear) -> {
+                if (isNear != null && isNear) {
                     // In pocket, drop event.
                     mDozeLog.traceSensorEventDropped(pulseReason, "prox reporting near");
                     return;
@@ -410,8 +409,8 @@
         sWakeDisplaySensorState = wake;
 
         if (wake) {
-            proximityCheckThenCall((result) -> {
-                if (result != null && result) {
+            proximityCheckThenCall((isNear) -> {
+                if (isNear != null && isNear) {
                     // In pocket, drop event.
                     return;
                 }
@@ -537,24 +536,44 @@
             return;
         }
 
-        if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
-            if (mAllowPulseTriggers) {
-                mDozeLog.tracePulseDropped(mPulsePending, dozeState, mDozeHost.isPulsingBlocked());
+        if (!mAllowPulseTriggers || mDozeHost.isPulsePending() || !canPulse()) {
+            if (!mAllowPulseTriggers) {
+                mDozeLog.tracePulseDropped("requestPulse - !mAllowPulseTriggers");
+            } else if (mDozeHost.isPulsePending()) {
+                mDozeLog.tracePulseDropped("requestPulse - pulsePending");
+            } else if (!canPulse()) {
+                mDozeLog.tracePulseDropped("requestPulse", dozeState);
             }
             runIfNotNull(onPulseSuppressedListener);
             return;
         }
 
-        mPulsePending = true;
-        proximityCheckThenCall((result) -> {
-            if (result != null && result) {
+        mDozeHost.setPulsePending(true);
+        proximityCheckThenCall((isNear) -> {
+            if (isNear != null && isNear) {
                 // in pocket, abort pulse
-                mDozeLog.tracePulseDropped("inPocket");
-                mPulsePending = false;
+                mDozeLog.tracePulseDropped("requestPulse - inPocket");
+                mDozeHost.setPulsePending(false);
                 runIfNotNull(onPulseSuppressedListener);
             } else {
                 // not in pocket, continue pulsing
-                continuePulseRequest(reason);
+                final boolean isPulsePending = mDozeHost.isPulsePending();
+                mDozeHost.setPulsePending(false);
+                if (!isPulsePending || mDozeHost.isPulsingBlocked() || !canPulse()) {
+                    if (!isPulsePending) {
+                        mDozeLog.tracePulseDropped("continuePulseRequest - pulse no longer"
+                                + " pending, pulse was cancelled before it could start"
+                                + " transitioning to pulsing state.");
+                    } else if (mDozeHost.isPulsingBlocked()) {
+                        mDozeLog.tracePulseDropped("continuePulseRequest - pulsingBlocked");
+                    } else if (!canPulse()) {
+                        mDozeLog.tracePulseDropped("continuePulseRequest", mMachine.getState());
+                    }
+                    runIfNotNull(onPulseSuppressedListener);
+                    return;
+                }
+
+                mMachine.requestPulse(reason);
             }
         }, !mDozeParameters.getProxCheckBeforePulse() || performedProxCheck, reason);
 
@@ -569,16 +588,6 @@
                 || mMachine.getState() == DozeMachine.State.DOZE_AOD_DOCKED;
     }
 
-    private void continuePulseRequest(int reason) {
-        mPulsePending = false;
-        if (mDozeHost.isPulsingBlocked() || !canPulse()) {
-            mDozeLog.tracePulseDropped(mPulsePending, mMachine.getState(),
-                    mDozeHost.isPulsingBlocked());
-            return;
-        }
-        mMachine.requestPulse(reason);
-    }
-
     @Nullable
     private InstanceId getKeyguardSessionId() {
         return mSessionTracker.getSessionId(SESSION_KEYGUARD);
@@ -591,7 +600,7 @@
         pw.print(" notificationPulseTime=");
         pw.println(Formatter.formatShortElapsedTime(mContext, mNotificationPulseTime));
 
-        pw.println(" pulsePending=" + mPulsePending);
+        pw.println(" DozeHost#isPulsePending=" + mDozeHost.isPulsePending());
         pw.println("DozeSensors:");
         IndentingPrintWriter idpw = new IndentingPrintWriter(pw);
         idpw.increaseIndent();
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
index 9cd149b..5694f6d 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -18,7 +18,7 @@
 
 import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_IN_DURATION;
 import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATIONS_FADE_OUT_DURATION;
-import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN;
+import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.COMPLICATION_MARGIN_DEFAULT;
 import static com.android.systemui.dreams.complication.dagger.ComplicationHostViewModule.SCOPED_COMPLICATIONS_LAYOUT;
 
 import android.animation.Animator;
@@ -67,7 +67,7 @@
         private final Parent mParent;
         @Complication.Category
         private final int mCategory;
-        private final int mMargin;
+        private final int mDefaultMargin;
 
         /**
          * Default constructor. {@link Parent} allows for the {@link ViewEntry}'s surrounding
@@ -75,7 +75,7 @@
          */
         ViewEntry(View view, ComplicationLayoutParams layoutParams,
                 TouchInsetManager.TouchInsetSession touchSession, int category, Parent parent,
-                int margin) {
+                int defaultMargin) {
             mView = view;
             // Views that are generated programmatically do not have a unique id assigned to them
             // at construction. A new id is assigned here to enable ConstraintLayout relative
@@ -86,7 +86,7 @@
             mTouchInsetSession = touchSession;
             mCategory = category;
             mParent = parent;
-            mMargin = margin;
+            mDefaultMargin = defaultMargin;
 
             touchSession.addViewToTracking(mView);
         }
@@ -195,18 +195,19 @@
                 }
 
                 if (!isRoot) {
+                    final int margin = mLayoutParams.getMargin(mDefaultMargin);
                     switch(direction) {
                         case ComplicationLayoutParams.DIRECTION_DOWN:
-                            params.setMargins(0, mMargin, 0, 0);
+                            params.setMargins(0, margin, 0, 0);
                             break;
                         case ComplicationLayoutParams.DIRECTION_UP:
-                            params.setMargins(0, 0, 0, mMargin);
+                            params.setMargins(0, 0, 0, margin);
                             break;
                         case ComplicationLayoutParams.DIRECTION_END:
-                            params.setMarginStart(mMargin);
+                            params.setMarginStart(margin);
                             break;
                         case ComplicationLayoutParams.DIRECTION_START:
-                            params.setMarginEnd(mMargin);
+                            params.setMarginEnd(margin);
                             break;
                     }
                 }
@@ -263,7 +264,7 @@
             private final ComplicationLayoutParams mLayoutParams;
             private final int mCategory;
             private Parent mParent;
-            private int mMargin;
+            private int mDefaultMargin;
 
             Builder(View view, TouchInsetManager.TouchInsetSession touchSession,
                     ComplicationLayoutParams lp, @Complication.Category int category) {
@@ -302,8 +303,8 @@
              * Sets the margin that will be applied in the direction the complication is laid out
              * towards.
              */
-            Builder setMargin(int margin) {
-                mMargin = margin;
+            Builder setDefaultMargin(int margin) {
+                mDefaultMargin = margin;
                 return this;
             }
 
@@ -312,7 +313,7 @@
              */
             ViewEntry build() {
                 return new ViewEntry(mView, mLayoutParams, mTouchSession, mCategory, mParent,
-                        mMargin);
+                        mDefaultMargin);
             }
         }
 
@@ -472,7 +473,7 @@
     }
 
     private final ConstraintLayout mLayout;
-    private final int mMargin;
+    private final int mDefaultMargin;
     private final HashMap<ComplicationId, ViewEntry> mEntries = new HashMap<>();
     private final HashMap<Integer, PositionGroup> mPositions = new HashMap<>();
     private final TouchInsetManager.TouchInsetSession mSession;
@@ -483,12 +484,12 @@
     /** */
     @Inject
     public ComplicationLayoutEngine(@Named(SCOPED_COMPLICATIONS_LAYOUT) ConstraintLayout layout,
-            @Named(COMPLICATION_MARGIN) int margin,
+            @Named(COMPLICATION_MARGIN_DEFAULT) int defaultMargin,
             TouchInsetManager.TouchInsetSession session,
             @Named(COMPLICATIONS_FADE_IN_DURATION) int fadeInDuration,
             @Named(COMPLICATIONS_FADE_OUT_DURATION) int fadeOutDuration) {
         mLayout = layout;
-        mMargin = margin;
+        mDefaultMargin = defaultMargin;
         mSession = session;
         mFadeInDuration = fadeInDuration;
         mFadeOutDuration = fadeOutDuration;
@@ -537,7 +538,7 @@
         }
 
         final ViewEntry.Builder entryBuilder = new ViewEntry.Builder(view, mSession, lp, category)
-                .setMargin(mMargin);
+                .setDefaultMargin(mDefaultMargin);
 
         // Add position group if doesn't already exist
         final int position = lp.getPosition();
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
index 8e8cb72..a21eb19 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
@@ -51,6 +51,8 @@
     private static final int FIRST_POSITION = POSITION_TOP;
     private static final int LAST_POSITION = POSITION_END;
 
+    private static final int MARGIN_UNSPECIFIED = 0xFFFFFFFF;
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, prefix = { "DIRECTION_" }, value = {
             DIRECTION_UP,
@@ -77,6 +79,8 @@
 
     private final int mWeight;
 
+    private final int mMargin;
+
     private final boolean mSnapToGuide;
 
     // Do not allow specifying opposite positions
@@ -106,7 +110,24 @@
      */
     public ComplicationLayoutParams(int width, int height, @Position int position,
             @Direction int direction, int weight) {
-        this(width, height, position, direction, weight, false);
+        this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, false);
+    }
+
+    /**
+     * Constructs a {@link ComplicationLayoutParams}.
+     * @param width The width {@link android.view.View.MeasureSpec} for the view.
+     * @param height The height {@link android.view.View.MeasureSpec} for the view.
+     * @param position The place within the parent container where the view should be positioned.
+     * @param direction The direction the view should be laid out from either the parent container
+     *                  or preceding view.
+     * @param weight The weight that should be considered for this view when compared to other
+     *               views. This has an impact on the placement of the view but not the rendering of
+     *               the view.
+     * @param margin The margin to apply between complications.
+     */
+    public ComplicationLayoutParams(int width, int height, @Position int position,
+            @Direction int direction, int weight, int margin) {
+        this(width, height, position, direction, weight, margin, false);
     }
 
     /**
@@ -127,6 +148,28 @@
      */
     public ComplicationLayoutParams(int width, int height, @Position int position,
             @Direction int direction, int weight, boolean snapToGuide) {
+        this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, snapToGuide);
+    }
+
+    /**
+     * Constructs a {@link ComplicationLayoutParams}.
+     * @param width The width {@link android.view.View.MeasureSpec} for the view.
+     * @param height The height {@link android.view.View.MeasureSpec} for the view.
+     * @param position The place within the parent container where the view should be positioned.
+     * @param direction The direction the view should be laid out from either the parent container
+     *                  or preceding view.
+     * @param weight The weight that should be considered for this view when compared to other
+     *               views. This has an impact on the placement of the view but not the rendering of
+     *               the view.
+     * @param margin The margin to apply between complications.
+     * @param snapToGuide When set to {@code true}, the dimension perpendicular to the direction
+     *                    will be automatically set to align with a predetermined guide for that
+     *                    side. For example, if the complication is aligned to the top end and
+     *                    direction is down, then the width of the complication will be set to span
+     *                    from the end of the parent to the guide.
+     */
+    public ComplicationLayoutParams(int width, int height, @Position int position,
+            @Direction int direction, int weight, int margin, boolean snapToGuide) {
         super(width, height);
 
         if (!validatePosition(position)) {
@@ -142,6 +185,8 @@
 
         mWeight = weight;
 
+        mMargin = margin;
+
         mSnapToGuide = snapToGuide;
     }
 
@@ -153,6 +198,7 @@
         mPosition = source.mPosition;
         mDirection = source.mDirection;
         mWeight = source.mWeight;
+        mMargin = source.mMargin;
         mSnapToGuide = source.mSnapToGuide;
     }
 
@@ -215,6 +261,14 @@
     }
 
     /**
+     * Returns the margin to apply between complications, or the given default if no margin is
+     * specified.
+     */
+    public int getMargin(int defaultMargin) {
+        return mMargin == MARGIN_UNSPECIFIED ? defaultMargin : mMargin;
+    }
+
+    /**
      * Returns whether the complication's dimension perpendicular to direction should be
      * automatically set.
      */
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 2503d3c..821e13e 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
@@ -28,6 +28,9 @@
 import android.view.View;
 import android.widget.ImageView;
 
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.controls.dagger.ControlsComponent;
@@ -158,17 +161,38 @@
         private final Context mContext;
         private final ControlsComponent mControlsComponent;
 
+        private final UiEventLogger mUiEventLogger;
+
+        @VisibleForTesting
+        public enum DreamOverlayEvent implements UiEventLogger.UiEventEnum {
+            @UiEvent(doc = "The home controls on the screensaver has been tapped.")
+            DREAM_HOME_CONTROLS_TAPPED(1212);
+
+            private final int mId;
+
+            DreamOverlayEvent(int id) {
+                mId = id;
+            }
+
+            @Override
+            public int getId() {
+                return mId;
+            }
+        }
+
         @Inject
         DreamHomeControlsChipViewController(
                 @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
                 ActivityStarter activityStarter,
                 Context context,
-                ControlsComponent controlsComponent) {
+                ControlsComponent controlsComponent,
+                UiEventLogger uiEventLogger) {
             super(view);
 
             mActivityStarter = activityStarter;
             mContext = context;
             mControlsComponent = controlsComponent;
+            mUiEventLogger = uiEventLogger;
         }
 
         @Override
@@ -184,6 +208,8 @@
         private void onClickHomeControls(View v) {
             if (DEBUG) Log.d(TAG, "home controls complication tapped");
 
+            mUiEventLogger.log(DreamOverlayEvent.DREAM_HOME_CONTROLS_TAPPED);
+
             final Intent intent = new Intent(mContext, ControlsActivity.class)
                     .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
                     .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java
index 11d89d2..c9fecc9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/ComplicationHostViewModule.java
@@ -37,7 +37,7 @@
 @Module
 public abstract class ComplicationHostViewModule {
     public static final String SCOPED_COMPLICATIONS_LAYOUT = "scoped_complications_layout";
-    public static final String COMPLICATION_MARGIN = "complication_margin";
+    public static final String COMPLICATION_MARGIN_DEFAULT = "complication_margin_default";
     public static final String COMPLICATIONS_FADE_OUT_DURATION = "complications_fade_out_duration";
     public static final String COMPLICATIONS_FADE_IN_DURATION = "complications_fade_in_duration";
     public static final String COMPLICATIONS_RESTORE_TIMEOUT = "complication_restore_timeout";
@@ -58,7 +58,7 @@
     }
 
     @Provides
-    @Named(COMPLICATION_MARGIN)
+    @Named(COMPLICATION_MARGIN_DEFAULT)
     @DreamOverlayComponent.DreamOverlayScope
     static int providesComplicationPadding(@Main Resources resources) {
         return resources.getDimensionPixelSize(R.dimen.dream_overlay_complication_margin);
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 759d6ec..7d2ce51 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
@@ -59,11 +59,11 @@
     @Named(DREAM_CLOCK_TIME_COMPLICATION_LAYOUT_PARAMS)
     static ComplicationLayoutParams provideClockTimeLayoutParams() {
         return new ComplicationLayoutParams(0,
-            ViewGroup.LayoutParams.WRAP_CONTENT,
-            ComplicationLayoutParams.POSITION_TOP
-                    | ComplicationLayoutParams.POSITION_START,
-            ComplicationLayoutParams.DIRECTION_DOWN,
-            DREAM_CLOCK_TIME_COMPLICATION_WEIGHT);
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ComplicationLayoutParams.POSITION_TOP
+                        | ComplicationLayoutParams.POSITION_START,
+                ComplicationLayoutParams.DIRECTION_DOWN,
+                DREAM_CLOCK_TIME_COMPLICATION_WEIGHT);
     }
 
     /**
@@ -73,12 +73,12 @@
     @Named(DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS)
     static ComplicationLayoutParams provideHomeControlsChipLayoutParams(@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_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT);
+                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_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT);
     }
 
     /**
@@ -103,11 +103,12 @@
     @Named(DREAM_SMARTSPACE_LAYOUT_PARAMS)
     static ComplicationLayoutParams provideSmartspaceLayoutParams() {
         return new ComplicationLayoutParams(0,
-            ViewGroup.LayoutParams.WRAP_CONTENT,
-            ComplicationLayoutParams.POSITION_TOP
-                    | ComplicationLayoutParams.POSITION_START,
-            ComplicationLayoutParams.DIRECTION_DOWN,
-            DREAM_SMARTSPACE_COMPLICATION_WEIGHT,
-            true /*snapToGuide*/);
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ComplicationLayoutParams.POSITION_TOP
+                        | ComplicationLayoutParams.POSITION_START,
+                ComplicationLayoutParams.DIRECTION_DOWN,
+                DREAM_SMARTSPACE_COMPLICATION_WEIGHT,
+                0,
+                true /*snapToGuide*/);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
index dfa3bcd..fb4fc92 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlags.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.flags
 
+import android.util.Dumpable
+
 /**
  * Class to manage simple DeviceConfig-based feature flags.
  *
  * See [Flags] for instructions on defining new flags.
  */
-interface FeatureFlags : FlagListenable {
+interface FeatureFlags : FlagListenable, Dumpable {
     /** Returns a boolean value for the given flag.  */
     fun isEnabled(flag: UnreleasedFlag): Boolean
 
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index 00c1a99..b983e5c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -30,29 +30,21 @@
 import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.os.Bundle;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.statusbar.commandline.Command;
-import com.android.systemui.statusbar.commandline.CommandRegistry;
 import com.android.systemui.util.DeviceConfigProxy;
 import com.android.systemui.util.settings.SecureSettings;
 
 import org.jetbrains.annotations.NotNull;
 
 import java.io.PrintWriter;
-import java.lang.reflect.Field;
 import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.TreeMap;
@@ -75,10 +67,9 @@
  * To restore a flag back to its default, leave the `--ez value <0|1>` off of the command.
  */
 @SysUISingleton
-public class FeatureFlagsDebug implements FeatureFlags, Dumpable {
-    private static final String TAG = "SysUIFlags";
+public class FeatureFlagsDebug implements FeatureFlags {
+    static final String TAG = "SysUIFlags";
     static final String ALL_FLAGS = "all_flags";
-    private static final String FLAG_COMMAND = "flag";
 
     private final FlagManager mFlagManager;
     private final SecureSettings mSecureSettings;
@@ -89,7 +80,7 @@
     private final Map<Integer, Flag<?>> mAllFlags;
     private final Map<Integer, Boolean> mBooleanFlagCache = new TreeMap<>();
     private final Map<Integer, String> mStringFlagCache = new TreeMap<>();
-    private final IStatusBarService mBarService;
+    private final Restarter mRestarter;
 
     @Inject
     public FeatureFlagsDebug(
@@ -98,12 +89,10 @@
             SecureSettings secureSettings,
             SystemPropertiesHelper systemProperties,
             @Main Resources resources,
-            DumpManager dumpManager,
             DeviceConfigProxy deviceConfigProxy,
             ServerFlagReader serverFlagReader,
             @Named(ALL_FLAGS) Map<Integer, Flag<?>> allFlags,
-            CommandRegistry commandRegistry,
-            IStatusBarService barService) {
+            Restarter barService) {
         mFlagManager = flagManager;
         mSecureSettings = secureSettings;
         mResources = resources;
@@ -111,7 +100,7 @@
         mDeviceConfigProxy = deviceConfigProxy;
         mServerFlagReader = serverFlagReader;
         mAllFlags = allFlags;
-        mBarService = barService;
+        mRestarter = barService;
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_SET_FLAG);
@@ -120,8 +109,6 @@
         flagManager.setClearCacheAction(this::removeFromCache);
         context.registerReceiver(mReceiver, filter, null, null,
                 Context.RECEIVER_EXPORTED_UNAUDITED);
-        dumpManager.registerDumpable(TAG, this);
-        commandRegistry.registerCommand(FLAG_COMMAND, FlagCommand::new);
     }
 
     @Override
@@ -266,7 +253,7 @@
         mFlagManager.dispatchListenersAndMaybeRestart(id, this::restartSystemUI);
     }
 
-    private <T> void eraseFlag(Flag<T> flag) {
+    <T> void eraseFlag(Flag<T> flag) {
         if (flag instanceof SysPropFlag) {
             mSystemProperties.erase(((SysPropFlag<T>) flag).getName());
             dispatchListenersAndMaybeRestart(flag.getId(), this::restartAndroid);
@@ -319,13 +306,10 @@
             return;
         }
         Log.i(TAG, "Restarting Android");
-        try {
-            mBarService.restart();
-        } catch (RemoteException e) {
-        }
+        mRestarter.restart();
     }
 
-    private void setBooleanFlagInternal(Flag<?> flag, boolean value) {
+    void setBooleanFlagInternal(Flag<?> flag, boolean value) {
         if (flag instanceof BooleanFlag) {
             setFlagValue(flag.getId(), value, BooleanFlagSerializer.INSTANCE);
         } else if (flag instanceof ResourceBooleanFlag) {
@@ -342,7 +326,7 @@
         }
     }
 
-    private void setStringFlagInternal(Flag<?> flag, String value) {
+    void setStringFlagInternal(Flag<?> flag, String value) {
         if (flag instanceof StringFlag) {
             setFlagValue(flag.getId(), value, StringFlagSerializer.INSTANCE);
         } else if (flag instanceof ResourceStringFlag) {
@@ -476,154 +460,4 @@
                 + ": [length=" + value.length() + "] \"" + value + "\""));
     }
 
-    class FlagCommand implements Command {
-        private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
-        private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
-
-        @Override
-        public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) {
-            if (args.size() == 0) {
-                pw.println("Error: no flag id supplied");
-                help(pw);
-                pw.println();
-                printKnownFlags(pw);
-                return;
-            }
-
-            if (args.size() > 2) {
-                pw.println("Invalid number of arguments.");
-                help(pw);
-                return;
-            }
-
-            int id = 0;
-            try {
-                id = Integer.parseInt(args.get(0));
-                if (!mAllFlags.containsKey(id)) {
-                    pw.println("Unknown flag id: " + id);
-                    pw.println();
-                    printKnownFlags(pw);
-                    return;
-                }
-            } catch (NumberFormatException e) {
-                id = flagNameToId(args.get(0));
-                if (id == 0) {
-                    pw.println("Invalid flag. Must an integer id or flag name: " + args.get(0));
-                    return;
-                }
-            }
-            Flag<?> flag = mAllFlags.get(id);
-
-            String cmd = "";
-            if (args.size() == 2) {
-                cmd = args.get(1).toLowerCase();
-            }
-
-            if ("erase".equals(cmd) || "reset".equals(cmd)) {
-                eraseFlag(flag);
-                return;
-            }
-
-            boolean newValue = true;
-            if (args.size() == 1 || "toggle".equals(cmd)) {
-                boolean enabled = isBooleanFlagEnabled(flag);
-
-                if (args.size() == 1) {
-                    pw.println("Flag " + id + " is " + enabled);
-                    return;
-                }
-
-                newValue = !enabled;
-            } else {
-                newValue = mOnCommands.contains(cmd);
-                if (!newValue && !mOffCommands.contains(cmd)) {
-                    pw.println("Invalid on/off argument supplied");
-                    help(pw);
-                    return;
-                }
-            }
-
-            pw.flush();  // Next command will restart sysui, so flush before we do so.
-            setBooleanFlagInternal(flag, newValue);
-        }
-
-        @Override
-        public void help(PrintWriter pw) {
-            pw.println(
-                    "Usage: adb shell cmd statusbar flag <id> "
-                            + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
-            pw.println("The id can either be a numeric integer or the corresponding field name");
-            pw.println(
-                    "If no argument is supplied after the id, the flags runtime value is output");
-        }
-
-        private boolean isBooleanFlagEnabled(Flag<?> flag) {
-            if (flag instanceof ReleasedFlag) {
-                return isEnabled((ReleasedFlag) flag);
-            } else if (flag instanceof UnreleasedFlag) {
-                return isEnabled((UnreleasedFlag) flag);
-            } else if (flag instanceof ResourceBooleanFlag) {
-                return isEnabled((ResourceBooleanFlag) flag);
-            } else if (flag instanceof SysPropFlag) {
-                return isEnabled((SysPropBooleanFlag) flag);
-            }
-
-            return false;
-        }
-
-        private int flagNameToId(String flagName) {
-            List<Field> fields = Flags.getFlagFields();
-            for (Field field : fields) {
-                if (flagName.equals(field.getName())) {
-                    return fieldToId(field);
-                }
-            }
-
-            return 0;
-        }
-
-        private int fieldToId(Field field) {
-            try {
-                Flag<?> flag = (Flag<?>) field.get(null);
-                return flag.getId();
-            } catch (IllegalAccessException e) {
-                // no-op
-            }
-
-            return 0;
-        }
-
-        private void printKnownFlags(PrintWriter pw) {
-            List<Field> fields = Flags.getFlagFields();
-
-            int longestFieldName = 0;
-            for (Field field : fields) {
-                longestFieldName = Math.max(longestFieldName, field.getName().length());
-            }
-
-            pw.println("Known Flags:");
-            pw.print("Flag Name");
-            for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
-                pw.print(" ");
-            }
-            pw.println("ID   Enabled?");
-            for (int i = 0; i < longestFieldName; i++) {
-                pw.print("=");
-            }
-            pw.println(" ==== ========");
-            for (Field field : fields) {
-                int id = fieldToId(field);
-                if (id == 0 || !mAllFlags.containsKey(id)) {
-                    continue;
-                }
-                pw.print(field.getName());
-                int fieldWidth = field.getName().length();
-                for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) {
-                    pw.print(" ");
-                }
-                pw.printf("%-4d ", id);
-                pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
new file mode 100644
index 0000000..c0e3021
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebugStartable.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import android.content.Context
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.commandline.CommandRegistry
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+
+class FeatureFlagsDebugStartable
+@Inject
+constructor(
+    @Application context: Context,
+    dumpManager: DumpManager,
+    private val commandRegistry: CommandRegistry,
+    private val flagCommand: FlagCommand,
+    featureFlags: FeatureFlags
+) : CoreStartable(context) {
+
+    init {
+        dumpManager.registerDumpable(FeatureFlagsDebug.TAG) { pw, args ->
+            featureFlags.dump(pw, args)
+        }
+    }
+
+    override fun start() {
+        commandRegistry.registerCommand(FlagCommand.FLAG_COMMAND) { flagCommand }
+    }
+}
+
+@Module
+abstract class FeatureFlagsDebugStartableModule {
+    @Binds
+    @IntoMap
+    @ClassKey(FeatureFlagsDebugStartable::class)
+    abstract fun bind(impl: FeatureFlagsDebugStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
index 049b17d..40a8a1a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsRelease.java
@@ -24,10 +24,8 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.util.DeviceConfigProxy;
 
 import org.jetbrains.annotations.NotNull;
@@ -44,27 +42,26 @@
  * how to set flags.
  */
 @SysUISingleton
-public class FeatureFlagsRelease implements FeatureFlags, Dumpable {
+public class FeatureFlagsRelease implements FeatureFlags {
+    static final String TAG = "SysUIFlags";
+
     private final Resources mResources;
     private final SystemPropertiesHelper mSystemProperties;
     private final DeviceConfigProxy mDeviceConfigProxy;
     private final ServerFlagReader mServerFlagReader;
     SparseBooleanArray mBooleanCache = new SparseBooleanArray();
     SparseArray<String> mStringCache = new SparseArray<>();
-    private boolean mInited;
 
     @Inject
     public FeatureFlagsRelease(
             @Main Resources resources,
             SystemPropertiesHelper systemProperties,
             DeviceConfigProxy deviceConfigProxy,
-            ServerFlagReader serverFlagReader,
-            DumpManager dumpManager) {
+            ServerFlagReader serverFlagReader) {
         mResources = resources;
         mSystemProperties = systemProperties;
         mDeviceConfigProxy = deviceConfigProxy;
         mServerFlagReader = serverFlagReader;
-        dumpManager.registerDumpable("SysUIFlags", this);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
new file mode 100644
index 0000000..f138f1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsReleaseStartable.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import android.content.Context
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dump.DumpManager
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+
+class FeatureFlagsReleaseStartable
+@Inject
+constructor(@Application context: Context, dumpManager: DumpManager, featureFlags: FeatureFlags) :
+    CoreStartable(context) {
+
+    init {
+        dumpManager.registerDumpable(FeatureFlagsRelease.TAG) { pw, args ->
+            featureFlags.dump(pw, args)
+        }
+    }
+
+    override fun start() {
+        // no-op
+    }
+}
+
+@Module
+abstract class FeatureFlagsReleaseStartableModule {
+    @Binds
+    @IntoMap
+    @ClassKey(FeatureFlagsReleaseStartable::class)
+    abstract fun bind(impl: FeatureFlagsReleaseStartable): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
new file mode 100644
index 0000000..4d25431
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagCommand.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.statusbar.commandline.Command;
+
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+/**
+ * A {@link Command} used to flip flags in SystemUI.
+ */
+public class FlagCommand implements Command {
+    public static final String FLAG_COMMAND = "flag";
+
+    private final List<String> mOnCommands = List.of("true", "on", "1", "enabled");
+    private final List<String> mOffCommands = List.of("false", "off", "0", "disable");
+    private final FeatureFlagsDebug mFeatureFlags;
+    private final Map<Integer, Flag<?>> mAllFlags;
+
+    @Inject
+    FlagCommand(
+            FeatureFlagsDebug featureFlags,
+            @Named(FeatureFlagsDebug.ALL_FLAGS) Map<Integer, Flag<?>> allFlags
+    ) {
+        mFeatureFlags = featureFlags;
+        mAllFlags = allFlags;
+    }
+
+    @Override
+    public void execute(@NonNull PrintWriter pw, @NonNull List<String> args) {
+        if (args.size() == 0) {
+            pw.println("Error: no flag id supplied");
+            help(pw);
+            pw.println();
+            printKnownFlags(pw);
+            return;
+        }
+
+        if (args.size() > 2) {
+            pw.println("Invalid number of arguments.");
+            help(pw);
+            return;
+        }
+
+        int id = 0;
+        try {
+            id = Integer.parseInt(args.get(0));
+            if (!mAllFlags.containsKey(id)) {
+                pw.println("Unknown flag id: " + id);
+                pw.println();
+                printKnownFlags(pw);
+                return;
+            }
+        } catch (NumberFormatException e) {
+            id = flagNameToId(args.get(0));
+            if (id == 0) {
+                pw.println("Invalid flag. Must an integer id or flag name: " + args.get(0));
+                return;
+            }
+        }
+        Flag<?> flag = mAllFlags.get(id);
+
+        String cmd = "";
+        if (args.size() == 2) {
+            cmd = args.get(1).toLowerCase();
+        }
+
+        if ("erase".equals(cmd) || "reset".equals(cmd)) {
+            mFeatureFlags.eraseFlag(flag);
+            return;
+        }
+
+        boolean newValue = true;
+        if (args.size() == 1 || "toggle".equals(cmd)) {
+            boolean enabled = isBooleanFlagEnabled(flag);
+
+            if (args.size() == 1) {
+                pw.println("Flag " + id + " is " + enabled);
+                return;
+            }
+
+            newValue = !enabled;
+        } else {
+            newValue = mOnCommands.contains(cmd);
+            if (!newValue && !mOffCommands.contains(cmd)) {
+                pw.println("Invalid on/off argument supplied");
+                help(pw);
+                return;
+            }
+        }
+
+        pw.flush();  // Next command will restart sysui, so flush before we do so.
+        mFeatureFlags.setBooleanFlagInternal(flag, newValue);
+    }
+
+    @Override
+    public void help(PrintWriter pw) {
+        pw.println(
+                "Usage: adb shell cmd statusbar flag <id> "
+                        + "[true|false|1|0|on|off|enable|disable|toggle|erase|reset]");
+        pw.println("The id can either be a numeric integer or the corresponding field name");
+        pw.println(
+                "If no argument is supplied after the id, the flags runtime value is output");
+    }
+
+    private boolean isBooleanFlagEnabled(Flag<?> flag) {
+        if (flag instanceof ReleasedFlag) {
+            return mFeatureFlags.isEnabled((ReleasedFlag) flag);
+        } else if (flag instanceof UnreleasedFlag) {
+            return mFeatureFlags.isEnabled((UnreleasedFlag) flag);
+        } else if (flag instanceof ResourceBooleanFlag) {
+            return mFeatureFlags.isEnabled((ResourceBooleanFlag) flag);
+        } else if (flag instanceof SysPropFlag) {
+            return mFeatureFlags.isEnabled((SysPropBooleanFlag) flag);
+        }
+
+        return false;
+    }
+
+    private int flagNameToId(String flagName) {
+        List<Field> fields = Flags.getFlagFields();
+        for (Field field : fields) {
+            if (flagName.equals(field.getName())) {
+                return fieldToId(field);
+            }
+        }
+
+        return 0;
+    }
+
+    private int fieldToId(Field field) {
+        try {
+            Flag<?> flag = (Flag<?>) field.get(null);
+            return flag.getId();
+        } catch (IllegalAccessException e) {
+            // no-op
+        }
+
+        return 0;
+    }
+
+    private void printKnownFlags(PrintWriter pw) {
+        List<Field> fields = Flags.getFlagFields();
+
+        int longestFieldName = 0;
+        for (Field field : fields) {
+            longestFieldName = Math.max(longestFieldName, field.getName().length());
+        }
+
+        pw.println("Known Flags:");
+        pw.print("Flag Name");
+        for (int i = 0; i < longestFieldName - "Flag Name".length() + 1; i++) {
+            pw.print(" ");
+        }
+        pw.println("ID   Enabled?");
+        for (int i = 0; i < longestFieldName; i++) {
+            pw.print("=");
+        }
+        pw.println(" ==== ========");
+        for (Field field : fields) {
+            int id = fieldToId(field);
+            if (id == 0 || !mAllFlags.containsKey(id)) {
+                continue;
+            }
+            pw.print(field.getName());
+            int fieldWidth = field.getName().length();
+            for (int i = 0; i < longestFieldName - fieldWidth + 1; i++) {
+                pw.print(" ");
+            }
+            pw.printf("%-4d ", id);
+            pw.println(isBooleanFlagEnabled(mAllFlags.get(id)));
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 48f5f9e..3868b6f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -68,7 +68,12 @@
 
     public static final UnreleasedFlag INSTANT_VOICE_REPLY = new UnreleasedFlag(111, true);
 
-    // next id: 112
+    public static final UnreleasedFlag NOTIFICATION_MEMORY_MONITOR_ENABLED = new UnreleasedFlag(112,
+            false);
+
+    public static final UnreleasedFlag NOTIFICATION_DISMISSAL_FADE = new UnreleasedFlag(113, true);
+
+    // next id: 114
 
     /***************************************/
     // 200 - keyguard/lockscreen
@@ -101,12 +106,28 @@
     public static final UnreleasedFlag MODERN_BOUNCER = new UnreleasedFlag(208);
 
     /** Whether UserSwitcherActivity should use modern architecture. */
-    public static final UnreleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
-            new UnreleasedFlag(209, true);
+    public static final ReleasedFlag MODERN_USER_SWITCHER_ACTIVITY =
+            new ReleasedFlag(209, true);
 
-    /** Whether the new implementation of UserSwitcherController should be used. */
-    public static final UnreleasedFlag REFACTORED_USER_SWITCHER_CONTROLLER =
-            new UnreleasedFlag(210, false);
+    /**
+     * Whether the user interactor and repository should use `UserSwitcherController`.
+     *
+     * <p>If this is {@code false}, the interactor and repo skip the controller and directly access
+     * the framework APIs.
+     */
+    public static final UnreleasedFlag USER_INTERACTOR_AND_REPO_USE_CONTROLLER =
+            new UnreleasedFlag(210);
+
+    /**
+     * Whether `UserSwitcherController` should use the user interactor.
+     *
+     * <p>When this is {@code true}, the controller does not directly access framework APIs.
+     * Instead, it goes through the interactor.
+     *
+     * <p>Note: do not set this to true if {@link #USER_INTERACTOR_AND_REPO_USE_CONTROLLER} is
+     * {@code true} as it would created a cycle between controller -> interactor -> controller.
+     */
+    public static final ReleasedFlag USER_CONTROLLER_USES_INTERACTOR = new ReleasedFlag(211);
 
     /***************************************/
     // 300 - power menu
@@ -152,7 +173,7 @@
     public static final ResourceBooleanFlag FULL_SCREEN_USER_SWITCHER =
             new ResourceBooleanFlag(506, R.bool.config_enableFullscreenUserSwitcher);
 
-    public static final UnreleasedFlag NEW_FOOTER_ACTIONS = new UnreleasedFlag(507, true);
+    public static final ReleasedFlag NEW_FOOTER_ACTIONS = new ReleasedFlag(507);
 
     /***************************************/
     // 600- status bar
@@ -189,14 +210,14 @@
     public static final UnreleasedFlag REGION_SAMPLING = new UnreleasedFlag(801);
 
     // 802 - wallpaper rendering
-    public static final UnreleasedFlag USE_CANVAS_RENDERER = new UnreleasedFlag(802);
+    public static final UnreleasedFlag USE_CANVAS_RENDERER = new UnreleasedFlag(802, true);
 
     // 803 - screen contents translation
     public static final UnreleasedFlag SCREEN_CONTENTS_TRANSLATION = new UnreleasedFlag(803);
 
     /***************************************/
     // 900 - media
-    public static final UnreleasedFlag MEDIA_TAP_TO_TRANSFER = new UnreleasedFlag(900);
+    public static final ReleasedFlag MEDIA_TAP_TO_TRANSFER = new ReleasedFlag(900);
     public static final UnreleasedFlag MEDIA_SESSION_ACTIONS = new UnreleasedFlag(901);
     public static final ReleasedFlag MEDIA_NEARBY_DEVICES = new ReleasedFlag(903);
     public static final ReleasedFlag MEDIA_MUTE_AWAIT = new ReleasedFlag(904);
@@ -208,7 +229,8 @@
             new ReleasedFlag(1000);
     public static final ReleasedFlag DOCK_SETUP_ENABLED = new ReleasedFlag(1001);
 
-    public static final UnreleasedFlag ROUNDED_BOX_RIPPLE = new UnreleasedFlag(1002, false);
+    public static final UnreleasedFlag ROUNDED_BOX_RIPPLE =
+            new UnreleasedFlag(1002, /* teamfood= */ true);
 
     // 1100 - windowing
     @Keep
@@ -247,6 +269,17 @@
     public static final SysPropBooleanFlag SHOW_FLOATING_TASKS_AS_BUBBLES =
             new SysPropBooleanFlag(1107, "persist.wm.debug.floating_tasks_as_bubbles", false);
 
+    @Keep
+    public static final SysPropBooleanFlag ENABLE_FLING_TO_DISMISS_BUBBLE =
+            new SysPropBooleanFlag(1108, "persist.wm.debug.fling_to_dismiss_bubble", true);
+    @Keep
+    public static final SysPropBooleanFlag ENABLE_FLING_TO_DISMISS_PIP =
+            new SysPropBooleanFlag(1109, "persist.wm.debug.fling_to_dismiss_pip", true);
+
+    @Keep
+    public static final SysPropBooleanFlag ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
+            new SysPropBooleanFlag(1110, "persist.wm.debug.enable_pip_keep_clear_algorithm", false);
+
     // 1200 - predictive back
     @Keep
     public static final SysPropBooleanFlag WM_ENABLE_PREDICTIVE_BACK = new SysPropBooleanFlag(
@@ -266,8 +299,8 @@
     public static final UnreleasedFlag SCREENSHOT_REQUEST_PROCESSOR = new UnreleasedFlag(1300);
     public static final UnreleasedFlag SCREENSHOT_WORK_PROFILE_POLICY = new UnreleasedFlag(1301);
 
-    // 1400 - columbus, b/242800729
-    public static final UnreleasedFlag QUICK_TAP_IN_PCC = new UnreleasedFlag(1400);
+    // 1400 - columbus
+    public static final ReleasedFlag QUICK_TAP_IN_PCC = new ReleasedFlag(1400);
 
     // 1500 - chooser
     public static final UnreleasedFlag CHOOSER_UNBUNDLED = new UnreleasedFlag(1500);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/flags/Restarter.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/flags/Restarter.kt
index 44c0496..8f095a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Restarter.kt
@@ -13,15 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.systemui.flags
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
-
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+interface Restarter {
+    fun restart()
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 6f38f4f..5f96a3b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -285,6 +285,14 @@
     var willUnlockWithInWindowLauncherAnimations: Boolean = false
 
     /**
+     * Whether we called [ILauncherUnlockAnimationController.prepareForUnlock], but have not yet
+     * called [ILauncherUnlockAnimationController.playUnlockAnimation]. This is used exclusively for
+     * logging purposes to help track down bugs where the Launcher surface is prepared for unlock
+     * but then never animated.
+     */
+    private var launcherPreparedForUnlock = false
+
+    /**
      * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
      * play the smartspace shared element animation. If true,
      * [willUnlockWithInWindowLauncherAnimations] will also always be true since in-window
@@ -376,6 +384,20 @@
     }
 
     /**
+     * Logging helper to log the conditions under which we decide to perform the in-window
+     * animations. This is used if we prepare to unlock but then somehow decide later to not play
+     * the animation, which would leave Launcher in a bad state.
+     */
+    private fun logInWindowAnimationConditions() {
+        Log.wtf(TAG, "canPerformInWindowLauncherAnimations expected all of these to be true: ")
+        Log.wtf(TAG, "  isNexusLauncherUnderneath: ${isNexusLauncherUnderneath()}")
+        Log.wtf(TAG, "  !notificationShadeWindowController.isLaunchingActivity: " +
+                "${!notificationShadeWindowController.isLaunchingActivity}")
+        Log.wtf(TAG, "  launcherUnlockController != null: ${launcherUnlockController != null}")
+        Log.wtf(TAG, "  !isFoldable(context): ${!isFoldable(context)}")
+    }
+
+    /**
      * Called from [KeyguardStateController] to let us know that the keyguard going away state has
      * changed.
      */
@@ -384,6 +406,15 @@
                 !statusBarStateController.leaveOpenOnKeyguardHide()) {
             prepareForInWindowLauncherAnimations()
         }
+
+        // If the keyguard is no longer going away and we were unlocking with in-window animations,
+        // make sure that we've left the launcher at 100% unlocked. This is a fail-safe to prevent
+        // against "tiny launcher" and similar states where the launcher is left in the prepared to
+        // animate state.
+        if (!keyguardStateController.isKeyguardGoingAway &&
+                willUnlockWithInWindowLauncherAnimations) {
+            launcherUnlockController?.setUnlockAmount(1f, true /* forceIfAnimating */)
+        }
     }
 
     /**
@@ -437,6 +468,8 @@
                 lockscreenSmartspaceBounds, /* lockscreenSmartspaceBounds */
                 selectedPage /* selectedPage */
             )
+
+            launcherPreparedForUnlock = true
         } catch (e: RemoteException) {
             Log.e(TAG, "Remote exception in prepareForInWindowUnlockAnimations.", e)
         }
@@ -495,6 +528,8 @@
                         true,
                         UNLOCK_ANIMATION_DURATION_MS + CANNED_UNLOCK_START_DELAY,
                         0 /* startDelay */)
+
+                launcherPreparedForUnlock = false
             } else {
                 // Otherwise, we're swiping in an app and should just fade it in. The swipe gesture
                 // will translate it until the end of the swipe gesture.
@@ -554,6 +589,12 @@
                 surfaceBehindEntryAnimator.start()
             }
         }
+
+        if (launcherPreparedForUnlock && !willUnlockWithInWindowLauncherAnimations) {
+            Log.wtf(TAG, "Launcher is prepared for unlock, so we should have started the " +
+                    "in-window animation, however we apparently did not.")
+            logInWindowAnimationConditions()
+        }
     }
 
     /**
@@ -569,6 +610,8 @@
             LAUNCHER_ICONS_ANIMATION_DURATION_MS /* duration */,
             CANNED_UNLOCK_START_DELAY /* startDelay */)
 
+        launcherPreparedForUnlock = false
+
         // Now that the Launcher surface (with its smartspace positioned identically to ours) is
         // visible, hide our smartspace.
         lockscreenSmartspace?.visibility = View.INVISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 38b98eb..da0b910 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -25,7 +25,6 @@
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_OCCLUSION;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_UNLOCK_ANIMATION;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -512,9 +511,9 @@
     KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
+        public void onKeyguardVisibilityChanged(boolean visible) {
             synchronized (KeyguardViewMediator.this) {
-                if (!showing && mPendingPinLock) {
+                if (!visible && mPendingPinLock) {
                     Log.i(TAG, "PIN lock requested, starting keyguard");
 
                     // Bring the keyguard back in order to show the PIN lock
@@ -804,9 +803,6 @@
             } else if (trustAgentsEnabled
                     && (strongAuth & SOME_AUTH_REQUIRED_AFTER_USER_REQUEST) != 0) {
                 return KeyguardSecurityView.PROMPT_REASON_USER_REQUEST;
-            } else if (trustAgentsEnabled
-                    && (strongAuth & SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED) != 0) {
-                return KeyguardSecurityView.PROMPT_REASON_TRUSTAGENT_EXPIRED;
             } else if (any && ((strongAuth & STRONG_AUTH_REQUIRED_AFTER_LOCKOUT) != 0
                     || mUpdateMonitor.isFingerprintLockedOut())) {
                 return KeyguardSecurityView.PROMPT_REASON_AFTER_LOCKOUT;
@@ -987,9 +983,11 @@
 
                 @Override
                 public void onAnimationCancelled(boolean isKeyguardOccluded) {
-                    if (mUnoccludeAnimator != null) {
-                        mUnoccludeAnimator.cancel();
-                    }
+                    mContext.getMainExecutor().execute(() -> {
+                        if (mUnoccludeAnimator != null) {
+                            mUnoccludeAnimator.cancel();
+                        }
+                    });
 
                     setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
                     Log.d(TAG, "Unocclude animation cancelled. Occluded state is now: "
@@ -1808,7 +1806,6 @@
 
             if (mOccluded != isOccluded) {
                 mOccluded = isOccluded;
-                mUpdateMonitor.setKeyguardOccluded(isOccluded);
                 mKeyguardViewControllerLazy.get().setOccluded(isOccluded, animate
                         && mDeviceInteractive);
                 adjustStatusBarLocked();
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 840a4b2..45b668e 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
@@ -85,6 +85,15 @@
      */
     val dozeAmount: Flow<Float>
 
+    /**
+     * Returns `true` if the keyguard is showing; `false` otherwise.
+     *
+     * Note: this is also `true` when the lock-screen is occluded with an `Activity` "above" it in
+     * the z-order (which is not really above the system UI window, but rather - the lock-screen
+     * becomes invisible to reveal the "occluding activity").
+     */
+    fun isKeyguardShowing(): Boolean
+
     /** Sets whether the bottom area UI should animate the transition out of doze state. */
     fun setAnimateDozingTransitions(animate: Boolean)
 
@@ -103,7 +112,7 @@
 @Inject
 constructor(
     statusBarStateController: StatusBarStateController,
-    keyguardStateController: KeyguardStateController,
+    private val keyguardStateController: KeyguardStateController,
     dozeHost: DozeHost,
 ) : KeyguardRepository {
     private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
@@ -148,7 +157,11 @@
                         }
                     }
                 dozeHost.addCallback(callback)
-                trySendWithFailureLogging(false, TAG, "initial isDozing: false")
+                trySendWithFailureLogging(
+                    statusBarStateController.isDozing,
+                    TAG,
+                    "initial isDozing",
+                )
 
                 awaitClose { dozeHost.removeCallback(callback) }
             }
@@ -168,6 +181,10 @@
         awaitClose { statusBarStateController.removeCallback(callback) }
     }
 
+    override fun isKeyguardShowing(): Boolean {
+        return keyguardStateController.isShowing
+    }
+
     override fun setAnimateDozingTransitions(animate: Boolean) {
         _animateBottomAreaDozingTransitions.value = animate
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index dccc941..192919e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -29,7 +29,7 @@
 class KeyguardInteractor
 @Inject
 constructor(
-    repository: KeyguardRepository,
+    private val repository: KeyguardRepository,
 ) {
     /**
      * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
@@ -40,4 +40,8 @@
     val isDozing: Flow<Boolean> = repository.isDozing
     /** Whether the keyguard is showing ot not. */
     val isKeyguardShowing: Flow<Boolean> = repository.isKeyguardShowing
+
+    fun isKeyguardShowing(): Boolean {
+        return repository.isKeyguardShowing()
+    }
 }
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 95acc0b..01cd3e2 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
@@ -104,7 +104,6 @@
                 KeyguardQuickAffordanceModel.Visible(
                     configKey = configs[index]::class,
                     icon = visibleState.icon,
-                    contentDescriptionResourceId = visibleState.contentDescriptionResourceId,
                 )
             } else {
                 KeyguardQuickAffordanceModel.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
index eff1469..eb6bb92 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/model/KeyguardQuickAffordanceModel.kt
@@ -17,8 +17,7 @@
 
 package com.android.systemui.keyguard.domain.model
 
-import androidx.annotation.StringRes
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
 import kotlin.reflect.KClass
 
@@ -35,11 +34,6 @@
         /** Identifier for the affordance this is modeling. */
         val configKey: KClass<out KeyguardQuickAffordanceConfig>,
         /** An icon for the affordance. */
-        val icon: ContainedDrawable,
-        /**
-         * Resource ID for a string to use for the accessibility content description text of the
-         * affordance.
-         */
-        @StringRes val contentDescriptionResourceId: Int,
+        val icon: Icon,
     ) : KeyguardQuickAffordanceModel()
 }
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 ac2c9b1..89604f0 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
@@ -23,7 +23,8 @@
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.controller.StructureInfo
 import com.android.systemui.controls.dagger.ControlsComponent
@@ -122,8 +123,14 @@
                 visibility == ControlsComponent.Visibility.AVAILABLE
         ) {
             KeyguardQuickAffordanceConfig.State.Visible(
-                icon = ContainedDrawable.WithResource(iconResourceId),
-                contentDescriptionResourceId = component.getTileTitleId(),
+                icon =
+                    Icon.Resource(
+                        res = iconResourceId,
+                        contentDescription =
+                            ContentDescription.Resource(
+                                res = component.getTileTitleId(),
+                            ),
+                    ),
             )
         } else {
             KeyguardQuickAffordanceConfig.State.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 8fb952c..8e1c6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -18,9 +18,8 @@
 package com.android.systemui.keyguard.domain.quickaffordance
 
 import android.content.Intent
-import androidx.annotation.StringRes
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.Icon
 import kotlinx.coroutines.flow.Flow
 
 /** Defines interface that can act as data source for a single quick affordance model. */
@@ -44,12 +43,7 @@
         /** An affordance is visible. */
         data class Visible(
             /** An icon for the affordance. */
-            val icon: ContainedDrawable,
-            /**
-             * Resource ID for a string to use for the accessibility content description text of the
-             * affordance.
-             */
-            @StringRes val contentDescriptionResourceId: Int,
+            val icon: Icon,
         ) : State()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
index c8e5e4a..d97deaf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfig.kt
@@ -21,7 +21,8 @@
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.containeddrawable.ContainedDrawable
+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.qrcodescanner.controller.QRCodeScannerController
 import javax.inject.Inject
@@ -76,8 +77,14 @@
     private fun state(): KeyguardQuickAffordanceConfig.State {
         return if (controller.isEnabledForLockScreenButton) {
             KeyguardQuickAffordanceConfig.State.Visible(
-                icon = ContainedDrawable.WithResource(R.drawable.ic_qr_code_scanner),
-                contentDescriptionResourceId = R.string.accessibility_qr_code_scanner_button,
+                icon =
+                    Icon.Resource(
+                        res = R.drawable.ic_qr_code_scanner,
+                        contentDescription =
+                            ContentDescription.Resource(
+                                res = R.string.accessibility_qr_code_scanner_button,
+                            ),
+                    ),
             )
         } else {
             KeyguardQuickAffordanceConfig.State.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
index 885af33..9196b09 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt
@@ -26,7 +26,8 @@
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.containeddrawable.ContainedDrawable
+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.plugins.ActivityStarter
 import com.android.systemui.wallet.controller.QuickAccessWalletController
@@ -100,8 +101,14 @@
     ): KeyguardQuickAffordanceConfig.State {
         return if (isFeatureEnabled && hasCard && tileIcon != null) {
             KeyguardQuickAffordanceConfig.State.Visible(
-                icon = ContainedDrawable.WithDrawable(tileIcon),
-                contentDescriptionResourceId = R.string.accessibility_wallet_button,
+                icon =
+                    Icon.Loaded(
+                        drawable = tileIcon,
+                        contentDescription =
+                            ContentDescription.Resource(
+                                res = R.string.accessibility_wallet_button,
+                            ),
+                    ),
             )
         } else {
             KeyguardQuickAffordanceConfig.State.Hidden
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index c4e3d4e..65b85c0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -31,7 +31,7 @@
 import com.android.systemui.R
 import com.android.systemui.animation.ActivityLaunchAnimator
 import com.android.systemui.animation.Interpolators
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel
 import com.android.systemui.lifecycle.repeatWhenAttached
@@ -236,10 +236,7 @@
             }
         }
 
-        when (viewModel.icon) {
-            is ContainedDrawable.WithDrawable -> view.setImageDrawable(viewModel.icon.drawable)
-            is ContainedDrawable.WithResource -> view.setImageResource(viewModel.icon.resourceId)
-        }
+        IconViewBinder.bind(viewModel.icon, view)
 
         view.drawable.setTint(
             Utils.getColorAttrDefaultColor(
@@ -250,7 +247,6 @@
         view.backgroundTintList =
             Utils.getColorAttr(view.context, com.android.internal.R.attr.colorSurface)
 
-        view.contentDescription = view.context.getString(viewModel.contentDescriptionResourceId)
         view.isClickable = viewModel.isClickable
         if (viewModel.isClickable) {
             view.setOnClickListener(OnClickListener(viewModel, falsingManager))
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
index e3ebac6..970ee4c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModel.kt
@@ -116,7 +116,6 @@
                     isVisible = true,
                     animateReveal = animateReveal,
                     icon = icon,
-                    contentDescriptionResourceId = contentDescriptionResourceId,
                     onClicked = { parameters ->
                         quickAffordanceInteractor.onQuickAffordanceClicked(
                             configKey = parameters.configKey,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
index b1de27d..0971f13 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardQuickAffordanceViewModel.kt
@@ -16,9 +16,8 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
-import androidx.annotation.StringRes
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.domain.quickaffordance.KeyguardQuickAffordanceConfig
 import kotlin.reflect.KClass
 
@@ -28,8 +27,7 @@
     val isVisible: Boolean = false,
     /** Whether to animate the transition of the quick affordance from invisible to visible. */
     val animateReveal: Boolean = false,
-    val icon: ContainedDrawable = ContainedDrawable.WithResource(0),
-    @StringRes val contentDescriptionResourceId: Int = 0,
+    val icon: Icon = Icon.Resource(res = 0, contentDescription = null),
     val onClicked: (OnClickedParameters) -> Unit = {},
     val isClickable: Boolean = false,
 ) {
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardLog.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardLog.kt
new file mode 100644
index 0000000..aef3471
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/KeyguardLog.kt
@@ -0,0 +1,10 @@
+package com.android.systemui.log.dagger
+
+import javax.inject.Qualifier
+
+/**
+ * A [com.android.systemui.log.LogBuffer] for keyguard-related stuff. Should be used mostly for
+ * adding temporary logs or logging from smaller classes when creating new separate log class might
+ * be an overkill.
+ */
+@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class KeyguardLog
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 29e2c1c..529d066 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -43,7 +43,7 @@
     @SysUISingleton
     @DozeLog
     public static LogBuffer provideDozeLogBuffer(LogBufferFactory factory) {
-        return factory.create("DozeLog", 100);
+        return factory.create("DozeLog", 120);
     }
 
     /** Provides a logging buffer for all logs related to the data layer of notifications. */
@@ -322,7 +322,7 @@
     @SysUISingleton
     @KeyguardUpdateMonitorLog
     public static LogBuffer provideKeyguardUpdateMonitorLogBuffer(LogBufferFactory factory) {
-        return factory.create("KeyguardUpdateMonitorLog", 200);
+        return factory.create("KeyguardUpdateMonitorLog", 400);
     }
 
     /**
@@ -334,4 +334,14 @@
     public static LogBuffer providerBluetoothLogBuffer(LogBufferFactory factory) {
         return factory.create("BluetoothLog", 50);
     }
+
+    /**
+     * Provides a {@link LogBuffer} for general keyguard-related logs.
+     */
+    @Provides
+    @SysUISingleton
+    @KeyguardLog
+    public static LogBuffer provideKeyguardLogBuffer(LogBufferFactory factory) {
+        return factory.create("KeyguardLog", 250);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index f8c6a57..9dd18b2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -149,32 +149,6 @@
                 }
             }
         }
-
-    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
@@ -475,7 +449,7 @@
         val existingPlayer = MediaPlayerData.getMediaPlayer(key)
         val curVisibleMediaKey = MediaPlayerData.playerKeys()
                 .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
-        val isCurVisibleMediaPlaying = MediaPlayerData.getMediaData(curVisibleMediaKey)?.isPlaying
+        val isCurVisibleMediaPlaying = curVisibleMediaKey?.data?.isPlaying
         if (existingPlayer == null) {
             val newPlayer = mediaControlPanelFactory.get()
             newPlayer.attachPlayer(MediaViewHolder.create(
@@ -912,7 +886,8 @@
                     interactedSubcardRank,
                     interactedSubcardCardinality,
                     receivedLatencyMillis,
-                    null // Media cards cannot have subcards.
+                    null, // Media cards cannot have subcards.
+                    null // Media cards don't have dimensions today.
             )
             /* ktlint-disable max-line-length */
             if (DEBUG) {
@@ -1068,15 +1043,6 @@
         }
     }
 
-    fun getMediaData(mediaSortKey: MediaSortKey?): MediaData? {
-        mediaData.forEach { (key, value) ->
-            if (value == mediaSortKey) {
-                return mediaData[key]?.data
-            }
-        }
-        return null
-    }
-
     fun getMediaPlayer(key: String): MediaControlPanel? {
         return mediaData.get(key)?.let { mediaPlayers.get(it) }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
index c6bd777..1ac2a07 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
@@ -17,6 +17,7 @@
 
 import android.app.ActivityOptions
 import android.content.Intent
+import android.content.res.Configuration
 import android.media.projection.IMediaProjection
 import android.media.projection.MediaProjectionManager.EXTRA_MEDIA_PROJECTION
 import android.os.Binder
@@ -24,85 +25,73 @@
 import android.os.IBinder
 import android.os.ResultReceiver
 import android.os.UserHandle
-import android.view.LayoutInflater
-import android.view.View
 import android.view.ViewGroup
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
 import com.android.internal.annotations.VisibleForTesting
 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.systemui.R
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorComponent
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
 import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorView
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
-import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter
-import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter.RecentTaskClickListener
+import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController
+import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.AsyncActivityLauncher
-import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration
 import javax.inject.Inject
 
 class MediaProjectionAppSelectorActivity(
+    private val componentFactory: MediaProjectionAppSelectorComponent.Factory,
     private val activityLauncher: AsyncActivityLauncher,
-    private val controller: MediaProjectionAppSelectorController,
-    private val recentTasksAdapterFactory: RecentTasksAdapter.Factory,
     /** This is used to override the dependency in a screenshot test */
     @VisibleForTesting
     private val listControllerFactory: ((userHandle: UserHandle) -> ResolverListController)?
-) : ChooserActivity(), MediaProjectionAppSelectorView, RecentTaskClickListener {
+) : ChooserActivity(), MediaProjectionAppSelectorView, MediaProjectionAppSelectorResultHandler {
 
     @Inject
     constructor(
+        componentFactory: MediaProjectionAppSelectorComponent.Factory,
         activityLauncher: AsyncActivityLauncher,
-        controller: MediaProjectionAppSelectorController,
-        recentTasksAdapterFactory: RecentTasksAdapter.Factory,
-    ) : this(activityLauncher, controller, recentTasksAdapterFactory, null)
+    ) : this(componentFactory, activityLauncher, null)
 
-    private var recentsRoot: ViewGroup? = null
-    private var recentsProgress: View? = null
-    private var recentsRecycler: RecyclerView? = null
+    private lateinit var configurationController: ConfigurationController
+    private lateinit var controller: MediaProjectionAppSelectorController
+    private lateinit var recentsViewController: MediaProjectionRecentsViewController
 
-    override fun getLayoutResource() =
-        R.layout.media_projection_app_selector
+    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)
+        val component =
+            componentFactory.create(
+                activity = this,
+                view = this,
+                resultHandler = this
+            )
+
+        // Create a separate configuration controller for this activity as the configuration
+        // might be different from the global one
+        configurationController = component.configurationController
+        controller = component.controller
+        recentsViewController = component.recentsViewController
+
+        val queryIntent = Intent(Intent.ACTION_MAIN).apply { addCategory(Intent.CATEGORY_LAUNCHER) }
         intent.putExtra(Intent.EXTRA_INTENT, queryIntent)
 
         // TODO(b/240939253): update copies
         val title = getString(R.string.media_projection_dialog_service_title)
         intent.putExtra(Intent.EXTRA_TITLE, title)
         super.onCreate(bundle)
-        controller.init(this)
+        controller.init()
     }
 
-    private fun createRecentsView(parent: ViewGroup): ViewGroup {
-        val recentsRoot = LayoutInflater.from(this)
-            .inflate(R.layout.media_projection_recent_tasks, parent,
-                    /* attachToRoot= */ false) as ViewGroup
-
-        recentsProgress = recentsRoot.requireViewById(R.id.media_projection_recent_tasks_loader)
-        recentsRecycler = recentsRoot.requireViewById(R.id.media_projection_recent_tasks_recycler)
-        recentsRecycler?.layoutManager = LinearLayoutManager(
-            this, LinearLayoutManager.HORIZONTAL,
-            /* reverseLayout= */false
-        )
-
-        val itemDecoration = HorizontalSpacerItemDecoration(
-            resources.getDimensionPixelOffset(
-                R.dimen.media_projection_app_selector_recents_padding
-            )
-        )
-        recentsRecycler?.addItemDecoration(itemDecoration)
-
-        return recentsRoot
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        configurationController.onConfigurationChanged(newConfig)
     }
 
-    override fun appliedThemeResId(): Int =
-        R.style.Theme_SystemUI_MediaProjectionAppSelector
+    override fun appliedThemeResId(): Int = R.style.Theme_SystemUI_MediaProjectionAppSelector
 
     override fun createListController(userHandle: UserHandle): ResolverListController =
         listControllerFactory?.invoke(userHandle) ?: super.createListController(userHandle)
@@ -124,9 +113,9 @@
         // is typically very fast, so we don't show any loaders.
         // We wait for the activity to be launched to make sure that the window of the activity
         // is created and ready to be captured.
-        val activityStarted = activityLauncher
-            .startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
-                onTargetActivityLaunched(launchToken)
+        val activityStarted =
+            activityLauncher.startActivityAsUser(intent, userHandle, activityOptions.toBundle()) {
+                returnSelectedApp(launchToken)
             }
 
         // Rely on the ActivityManager to pop up a dialog regarding app suspension
@@ -160,44 +149,27 @@
     }
 
     override fun bind(recentTasks: List<RecentTask>) {
-        val recents = recentsRoot ?: return
-        val progress = recentsProgress ?: return
-        val recycler = recentsRecycler ?: return
-
-        if (recentTasks.isEmpty()) {
-            recents.visibility = View.GONE
-            return
-        }
-
-        progress.visibility = View.GONE
-        recycler.visibility = View.VISIBLE
-        recents.visibility = View.VISIBLE
-
-        recycler.adapter = recentTasksAdapterFactory.create(recentTasks, this)
+        recentsViewController.bind(recentTasks)
     }
 
-    override fun onRecentClicked(task: RecentTask, view: View) {
-        // TODO(b/240924732) Handle clicking on a recent task
-    }
-
-    private fun onTargetActivityLaunched(launchToken: IBinder) {
+    override fun returnSelectedApp(launchCookie: IBinder) {
         if (intent.hasExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER)) {
             // The client requested to return the result in the result receiver instead of
             // activity result, let's send the media projection to the result receiver
-            val resultReceiver = intent
-                .getParcelableExtra(EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
-                    ResultReceiver::class.java) as ResultReceiver
-            val captureRegion = MediaProjectionCaptureTarget(launchToken)
-            val data = Bundle().apply {
-                putParcelable(KEY_CAPTURE_TARGET, captureRegion)
-            }
+            val resultReceiver =
+                intent.getParcelableExtra(
+                    EXTRA_CAPTURE_REGION_RESULT_RECEIVER,
+                    ResultReceiver::class.java
+                ) as ResultReceiver
+            val captureRegion = MediaProjectionCaptureTarget(launchCookie)
+            val data = Bundle().apply { putParcelable(KEY_CAPTURE_TARGET, captureRegion) }
             resultReceiver.send(RESULT_OK, data)
         } else {
             // Return the media projection instance as activity result
             val mediaProjectionBinder = intent.getIBinderExtra(EXTRA_MEDIA_PROJECTION)
             val projection = IMediaProjection.Stub.asInterface(mediaProjectionBinder)
 
-            projection.launchCookie = launchToken
+            projection.launchCookie = launchCookie
 
             val intent = Intent()
             intent.putExtra(EXTRA_MEDIA_PROJECTION, projection.asBinder())
@@ -214,15 +186,13 @@
     override fun shouldShowContentPreview() = false
 
     override fun createContentPreviewView(parent: ViewGroup): ViewGroup =
-            recentsRoot ?: createRecentsView(parent).also {
-                recentsRoot = it
-            }
+        recentsViewController.createView(parent)
 
     companion object {
         /**
-         * When EXTRA_CAPTURE_REGION_RESULT_RECEIVER is passed as intent extra
-         * the activity will send the [CaptureRegion] to the result receiver
-         * instead of returning media projection instance through activity result.
+         * When EXTRA_CAPTURE_REGION_RESULT_RECEIVER is passed as intent extra the activity will
+         * send the [CaptureRegion] to the result receiver instead of returning media projection
+         * instance through activity result.
          */
         const val EXTRA_CAPTURE_REGION_RESULT_RECEIVER = "capture_region_result_receiver"
         const val KEY_CAPTURE_TARGET = "capture_region"
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 0359c63..17ebfec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -30,7 +30,10 @@
 import androidx.core.view.GestureDetectorCompat
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
+import com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.FalsingManager.LOW_PENALTY
 import com.android.systemui.statusbar.NotificationMediaManager
 import com.android.systemui.util.concurrency.RepeatableExecutor
 import javax.inject.Inject
@@ -72,7 +75,8 @@
 
 /** ViewModel for seek bar in QS media player. */
 class SeekBarViewModel @Inject constructor(
-    @Background private val bgExecutor: RepeatableExecutor
+    @Background private val bgExecutor: RepeatableExecutor,
+    private val falsingManager: FalsingManager,
 ) {
     private var _data = Progress(false, false, false, false, null, 0)
         set(value) {
@@ -275,7 +279,7 @@
     /** Gets a listener to attach to the seek bar to handle seeking. */
     val seekBarListener: SeekBar.OnSeekBarChangeListener
         get() {
-            return SeekBarChangeListener(this)
+            return SeekBarChangeListener(this, falsingManager)
         }
 
     /** Attach touch handlers to the seek bar view. */
@@ -315,7 +319,8 @@
     }
 
     private class SeekBarChangeListener(
-        val viewModel: SeekBarViewModel
+        val viewModel: SeekBarViewModel,
+        val falsingManager: FalsingManager,
     ) : SeekBar.OnSeekBarChangeListener {
         override fun onProgressChanged(bar: SeekBar, progress: Int, fromUser: Boolean) {
             if (fromUser) {
@@ -328,6 +333,13 @@
         }
 
         override fun onStopTrackingTouch(bar: SeekBar) {
+            // in addition to the normal functionality of both functions.
+            // isFalseTouch returns true if there is a real/false tap since it is not a move.
+            // isFalseTap returns true if there is a real/false move since it is not a tap.
+            if (falsingManager.isFalseTouch(MEDIA_SEEKBAR) &&
+                    falsingManager.isFalseTap(LOW_PENALTY)) {
+                viewModel.onSeekFalse()
+            }
             viewModel.onSeek(bar.progress.toLong())
         }
     }
@@ -340,7 +352,7 @@
      */
     private class SeekBarTouchListener(
         private val viewModel: SeekBarViewModel,
-        private val bar: SeekBar
+        private val bar: SeekBar,
     ) : View.OnTouchListener, GestureDetector.OnGestureListener {
 
         // Gesture detector helps decide which touch events to intercept.
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
deleted file mode 100644
index 185b4fc..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
+++ /dev/null
@@ -1,89 +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.media.dagger
-
-import android.app.Activity
-import android.content.ComponentName
-import android.content.Context
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.media.MediaProjectionAppSelectorActivity
-import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorController
-import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
-import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
-import com.android.systemui.mediaprojection.appselector.data.IconLoaderLibAppIconLoader
-import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
-import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
-import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider
-import dagger.Binds
-import dagger.Module
-import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.SupervisorJob
-import javax.inject.Qualifier
-
-@Qualifier
-@Retention(AnnotationRetention.BINARY)
-annotation class MediaProjectionAppSelector
-
-@Module
-abstract class MediaProjectionModule {
-
-    @Binds
-    @IntoMap
-    @ClassKey(MediaProjectionAppSelectorActivity::class)
-    abstract fun provideMediaProjectionAppSelectorActivity(
-        activity: MediaProjectionAppSelectorActivity
-    ): Activity
-
-    @Binds
-    abstract fun bindRecentTaskThumbnailLoader(
-        impl: ActivityTaskManagerThumbnailLoader
-    ): RecentTaskThumbnailLoader
-
-    @Binds
-    abstract fun bindRecentTaskListProvider(
-        impl: ShellRecentTaskListProvider
-    ): RecentTaskListProvider
-
-    @Binds
-    abstract fun bindAppIconLoader(impl: IconLoaderLibAppIconLoader): AppIconLoader
-
-    companion object {
-        @Provides
-        fun provideController(
-            recentTaskListProvider: RecentTaskListProvider,
-            context: Context,
-            @MediaProjectionAppSelector scope: CoroutineScope
-        ): MediaProjectionAppSelectorController {
-            val appSelectorComponentName =
-                ComponentName(context, MediaProjectionAppSelectorActivity::class.java)
-
-            return MediaProjectionAppSelectorController(
-                recentTaskListProvider,
-                scope,
-                appSelectorComponentName
-            )
-        }
-
-        @MediaProjectionAppSelector
-        @Provides
-        fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope =
-            CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index 00b0ff9..f5caefb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -22,6 +22,7 @@
 import android.media.MediaRoute2Info
 import android.util.Log
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
@@ -39,14 +40,10 @@
  */
 @SysUISingleton
 class MediaTttCommandLineHelper @Inject constructor(
-    commandRegistry: CommandRegistry,
+    private val commandRegistry: CommandRegistry,
     private val context: Context,
     @Main private val mainExecutor: Executor
-) {
-    init {
-        commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
-        commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() }
-    }
+) : CoreStartable(context) {
 
     /** All commands for the sender device. */
     inner class SenderCommand : Command {
@@ -56,7 +53,7 @@
             val displayState: Int?
             try {
                 displayState = ChipStateSender.getSenderStateIdFromName(commandName)
-            }  catch (ex: IllegalArgumentException) {
+            } catch (ex: IllegalArgumentException) {
                 pw.println("Invalid command name $commandName")
                 return
             }
@@ -150,6 +147,11 @@
                     "<chipState> useAppIcon=[true|false]")
         }
     }
+
+    override fun start() {
+        commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
+        commandRegistry.registerCommand(RECEIVER_COMMAND) { ReceiverCommand() }
+    }
 }
 
 @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
index 792ae7c..c3de94f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttUtils.kt
@@ -19,7 +19,6 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
-import com.android.internal.widget.CachingIconView
 import com.android.settingslib.Utils
 import com.android.systemui.R
 
@@ -76,29 +75,6 @@
                 isAppIcon = false
             )
         }
-
-        /**
-         * Sets an icon to be displayed by the given view.
-         *
-         * @param iconSize the size in pixels that the icon should be. If null, the size of
-         * [appIconView] will not be adjusted.
-         */
-        fun setIcon(
-            appIconView: CachingIconView,
-            icon: Drawable,
-            iconContentDescription: CharSequence,
-            iconSize: Int? = null,
-        ) {
-            iconSize?.let { size ->
-                val lp = appIconView.layoutParams
-                lp.width = size
-                lp.height = size
-                appIconView.layoutParams = lp
-            }
-
-            appIconView.contentDescription = iconContentDescription
-            appIconView.setImageDrawable(icon)
-        }
     }
 }
 
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 dfd9e22..1461293 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
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint
 import android.app.StatusBarManager
 import android.content.Context
+import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.graphics.drawable.Icon
 import android.media.MediaRoute2Info
@@ -30,6 +31,7 @@
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
+import com.android.internal.widget.CachingIconView
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
@@ -43,6 +45,7 @@
 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
 
 /**
@@ -52,7 +55,7 @@
  */
 @SysUISingleton
 class MediaTttChipControllerReceiver @Inject constructor(
-        commandQueue: CommandQueue,
+        private val commandQueue: CommandQueue,
         context: Context,
         @MediaTttReceiverLogger logger: MediaTttLogger,
         windowManager: WindowManager,
@@ -62,6 +65,7 @@
         powerManager: PowerManager,
         @Main private val mainHandler: Handler,
         private val uiEventLogger: MediaTttReceiverUiEventLogger,
+        private val viewUtil: ViewUtil,
 ) : TemporaryViewDisplayController<ChipReceiverInfo, MediaTttLogger>(
         context,
         logger,
@@ -82,7 +86,6 @@
         height = WindowManager.LayoutParams.MATCH_PARENT
         layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
         fitInsetsTypes = 0 // Ignore insets from all system bars
-        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
     }
 
     private val commandQueueCallbacks = object : CommandQueue.Callbacks {
@@ -98,10 +101,6 @@
         }
     }
 
-    init {
-        commandQueue.addCallback(commandQueueCallbacks)
-    }
-
     private fun updateMediaTapToTransferReceiverDisplay(
         @StatusBarManager.MediaTransferReceiverState displayState: Int,
         routeInfo: MediaRoute2Info,
@@ -138,32 +137,31 @@
         )
     }
 
-    override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
-        super.updateView(newInfo, currentView)
+    override fun start() {
+        commandQueue.addCallback(commandQueueCallbacks)
+    }
 
+    override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
         val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
             context, newInfo.routeInfo.clientPackageName, logger
         )
         val iconDrawable = newInfo.appIconDrawableOverride ?: iconInfo.drawable
         val iconContentDescription = newInfo.appNameOverride ?: iconInfo.contentDescription
-        val iconSize = context.resources.getDimensionPixelSize(
+        val iconPadding =
             if (iconInfo.isAppIcon) {
-                R.dimen.media_ttt_icon_size_receiver
+                0
             } else {
-                R.dimen.media_ttt_generic_icon_size_receiver
+                context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_padding)
             }
-        )
 
-        MediaTttUtils.setIcon(
-            currentView.requireViewById(R.id.app_icon),
-            iconDrawable,
-            iconContentDescription,
-            iconSize,
-        )
+        val iconView = currentView.getAppIconView()
+        iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding)
+        iconView.setImageDrawable(iconDrawable)
+        iconView.contentDescription = iconContentDescription
     }
 
     override fun animateViewIn(view: ViewGroup) {
-        val appIconView = view.requireViewById<View>(R.id.app_icon)
+        val appIconView = view.getAppIconView()
         appIconView.animate()
                 .translationYBy(-1 * getTranslationAmount().toFloat())
                 .setDuration(30.frames)
@@ -177,6 +175,12 @@
         startRipple(view.requireViewById(R.id.ripple))
     }
 
+    override fun getTouchableRegion(view: View, outRect: Rect) {
+        // Even though the app icon view isn't touchable, users might think it is. So, use it as the
+        // touchable region to ensure that touches don't get passed to the window below.
+        viewUtil.setRectToViewWindowLocation(view.getAppIconView(), outRect)
+    }
+
     /** Returns the amount that the chip will be translated by in its intro animation. */
     private fun getTranslationAmount(): Int {
         return context.resources.getDimensionPixelSize(R.dimen.media_ttt_receiver_vert_translation)
@@ -204,16 +208,19 @@
 
     private fun layoutRipple(rippleView: ReceiverChipRippleView) {
         val windowBounds = windowManager.currentWindowMetrics.bounds
-        val height = windowBounds.height()
-        val width = windowBounds.width()
+        val height = windowBounds.height().toFloat()
+        val width = windowBounds.width().toFloat()
 
-        val maxDiameter = height / 2.5f
-        rippleView.setMaxSize(maxDiameter, maxDiameter)
+        rippleView.setMaxSize(width / 2f, height / 2f)
         // Center the ripple on the bottom of the screen in the middle.
-        rippleView.setCenter(width * 0.5f, height.toFloat())
+        rippleView.setCenter(width * 0.5f, height)
         val color = Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent)
         rippleView.setColor(color, 70)
     }
+
+    private fun View.getAppIconView(): CachingIconView {
+        return this.requireViewById(R.id.app_icon)
+    }
 }
 
 data class ChipReceiverInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
index 6a505f0..e354a03 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ReceiverChipRippleView.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.util.AttributeSet
+import com.android.systemui.ripple.RippleShader
 import com.android.systemui.ripple.RippleView
 
 /**
@@ -25,9 +26,9 @@
  */
 class ReceiverChipRippleView(context: Context?, attrs: AttributeSet?) : RippleView(context, attrs) {
     init {
-        // TODO: use RippleShape#ELLIPSE when calling setupShader.
-        setupShader()
+        setupShader(RippleShader.RippleShape.ELLIPSE)
         setRippleFill(true)
+        setSparkleStrength(0f)
         duration = 3000L
     }
 }
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 4379d25..aae973d 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,6 +25,7 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.statusbar.IUndoMediaTransferCallback
 import com.android.systemui.R
+import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
 
 /**
@@ -107,12 +108,15 @@
             controllerSender: MediaTttChipControllerSender,
             routeInfo: MediaRoute2Info,
             undoCallback: IUndoMediaTransferCallback?,
-            uiEventLogger: MediaTttSenderUiEventLogger
+            uiEventLogger: MediaTttSenderUiEventLogger,
+            falsingManager: FalsingManager,
         ): View.OnClickListener? {
             if (undoCallback == null) {
                 return null
             }
             return View.OnClickListener {
+                if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@OnClickListener
+
                 uiEventLogger.logUndoClicked(
                     MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_RECEIVER_CLICKED
                 )
@@ -143,12 +147,15 @@
             controllerSender: MediaTttChipControllerSender,
             routeInfo: MediaRoute2Info,
             undoCallback: IUndoMediaTransferCallback?,
-            uiEventLogger: MediaTttSenderUiEventLogger
+            uiEventLogger: MediaTttSenderUiEventLogger,
+            falsingManager: FalsingManager,
         ): View.OnClickListener? {
             if (undoCallback == null) {
                 return null
             }
             return View.OnClickListener {
+                if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@OnClickListener
+
                 uiEventLogger.logUndoClicked(
                     MediaTttSenderUiEvents.MEDIA_TTT_SENDER_UNDO_TRANSFER_TO_THIS_DEVICE_CLICKED
                 )
@@ -215,7 +222,8 @@
         controllerSender: MediaTttChipControllerSender,
         routeInfo: MediaRoute2Info,
         undoCallback: IUndoMediaTransferCallback?,
-        uiEventLogger: MediaTttSenderUiEventLogger
+        uiEventLogger: MediaTttSenderUiEventLogger,
+        falsingManager: FalsingManager,
     ): View.OnClickListener? = null
 
     companion object {
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 e539f3f..5d63145 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
@@ -18,29 +18,36 @@
 
 import android.app.StatusBarManager
 import android.content.Context
+import android.graphics.Rect
 import android.media.MediaRoute2Info
 import android.os.PowerManager
 import android.util.Log
 import android.view.Gravity
+import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
 import android.widget.TextView
 import com.android.internal.statusbar.IUndoMediaTransferCallback
+import com.android.internal.widget.CachingIconView
+import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.animation.ViewHierarchyAnimator
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.media.taptotransfer.common.MediaTttLogger
 import com.android.systemui.media.taptotransfer.common.MediaTttUtils
+import com.android.systemui.plugins.FalsingManager
 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
 
 /**
@@ -48,8 +55,8 @@
  * chip is shown when a user is transferring media to/from this device and a receiver device.
  */
 @SysUISingleton
-class MediaTttChipControllerSender @Inject constructor(
-        commandQueue: CommandQueue,
+open class MediaTttChipControllerSender @Inject constructor(
+        private val commandQueue: CommandQueue,
         context: Context,
         @MediaTttSenderLogger logger: MediaTttLogger,
         windowManager: WindowManager,
@@ -57,7 +64,10 @@
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
-        private val uiEventLogger: MediaTttSenderUiEventLogger
+        private val uiEventLogger: MediaTttSenderUiEventLogger,
+        private val falsingManager: FalsingManager,
+        private val falsingCollector: FalsingCollector,
+        private val viewUtil: ViewUtil,
 ) : TemporaryViewDisplayController<ChipSenderInfo, MediaTttLogger>(
         context,
         logger,
@@ -70,6 +80,9 @@
         MediaTttUtils.WINDOW_TITLE,
         MediaTttUtils.WAKE_REASON,
 ) {
+
+    private lateinit var parent: MediaTttChipRootView
+
     override val windowLayoutParams = commonWindowLayoutParams.apply {
         gravity = Gravity.TOP.or(Gravity.CENTER_HORIZONTAL)
     }
@@ -86,10 +99,6 @@
         }
     }
 
-    init {
-        commandQueue.addCallback(commandQueueCallbacks)
-    }
-
     private fun updateMediaTapToTransferSenderDisplay(
         @StatusBarManager.MediaTransferSenderState displayState: Int,
         routeInfo: MediaRoute2Info,
@@ -112,23 +121,32 @@
         }
     }
 
+    override fun start() {
+        commandQueue.addCallback(commandQueueCallbacks)
+    }
+
     override fun updateView(
         newInfo: ChipSenderInfo,
         currentView: ViewGroup
     ) {
-        super.updateView(newInfo, currentView)
-
         val chipState = newInfo.state
 
+        // Detect falsing touches on the chip.
+        parent = currentView.requireViewById(R.id.media_ttt_sender_chip)
+        parent.touchHandler = object : Gefingerpoken {
+            override fun onTouchEvent(ev: MotionEvent?): Boolean {
+                falsingCollector.onTouchEvent(ev)
+                return false
+            }
+        }
+
         // App icon
         val iconInfo = MediaTttUtils.getIconInfoFromPackageName(
             context, newInfo.routeInfo.clientPackageName, logger
         )
-        MediaTttUtils.setIcon(
-            currentView.requireViewById(R.id.app_icon),
-            iconInfo.drawable,
-            iconInfo.contentDescription
-        )
+        val iconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
+        iconView.setImageDrawable(iconInfo.drawable)
+        iconView.contentDescription = iconInfo.contentDescription
 
         // Text
         val otherDeviceName = newInfo.routeInfo.name.toString()
@@ -142,7 +160,11 @@
         // Undo
         val undoView = currentView.requireViewById<View>(R.id.undo)
         val undoClickListener = chipState.undoClickListener(
-                this, newInfo.routeInfo, newInfo.undoCallback, uiEventLogger
+                this,
+                newInfo.routeInfo,
+                newInfo.undoCallback,
+                uiEventLogger,
+                falsingManager,
         )
         undoView.setOnClickListener(undoClickListener)
         undoView.visibility = (undoClickListener != null).visibleIfTrue()
@@ -171,10 +193,22 @@
         )
     }
 
-    override fun removeView(removalReason: String) {
+    override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
+        ViewHierarchyAnimator.animateRemoval(
+            view.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner),
+            ViewHierarchyAnimator.Hotspot.TOP,
+            Interpolators.EMPHASIZED_ACCELERATE,
+            ANIMATION_DURATION,
+            onAnimationEnd,
+        )
+        // TODO(b/203800644): Add includeMargins as an option to ViewHierarchyAnimator so that the
+        //   animateChipOut matches the animateChipIn.
+    }
+
+    override fun shouldIgnoreViewRemoval(info: ChipSenderInfo, removalReason: String): Boolean {
         // Don't remove the chip if we're in progress or succeeded, since the user should still be
         // able to see the status of the transfer. (But do remove it if it's finally timed out.)
-        val transferStatus = info?.state?.transferStatus
+        val transferStatus = info.state.transferStatus
         if (
             (transferStatus == TransferStatus.IN_PROGRESS ||
                 transferStatus == TransferStatus.SUCCEEDED) &&
@@ -183,9 +217,13 @@
             logger.logRemovalBypass(
                 removalReason, bypassReason = "transferStatus=${transferStatus.name}"
             )
-            return
+            return true
         }
-        super.removeView(removalReason)
+        return false
+    }
+
+    override fun getTouchableRegion(view: View, outRect: Rect) {
+        viewUtil.setRectToViewWindowLocation(view, outRect)
     }
 
     private fun Boolean.visibleIfTrue(): Int {
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt
new file mode 100644
index 0000000..3373159
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipRootView.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.taptotransfer.sender
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.widget.FrameLayout
+import com.android.systemui.Gefingerpoken
+
+/** A simple subclass that allows for observing touch events on chip. */
+class MediaTttChipRootView(
+        context: Context,
+        attrs: AttributeSet?
+) : FrameLayout(context, attrs) {
+
+    /** Assign this field to observe touch events. */
+    var touchHandler: Gefingerpoken? = null
+
+    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
+        touchHandler?.onTouchEvent(ev)
+        return super.dispatchTouchEvent(ev)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
new file mode 100644
index 0000000..7fd100f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorComponent.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.appselector
+
+import android.app.Activity
+import android.content.ComponentName
+import android.content.Context
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.media.MediaProjectionAppSelectorActivity
+import com.android.systemui.mediaprojection.appselector.data.ActivityTaskManagerThumbnailLoader
+import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
+import com.android.systemui.mediaprojection.appselector.data.IconLoaderLibAppIconLoader
+import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
+import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
+import com.android.systemui.mediaprojection.appselector.data.ShellRecentTaskListProvider
+import com.android.systemui.mediaprojection.appselector.view.MediaProjectionRecentsViewController
+import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
+import com.android.systemui.statusbar.policy.ConfigurationController
+import dagger.Binds
+import dagger.BindsInstance
+import dagger.Module
+import dagger.Provides
+import dagger.Subcomponent
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Qualifier
+import javax.inject.Scope
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
+
+@Qualifier @Retention(AnnotationRetention.BINARY) annotation class MediaProjectionAppSelector
+
+@Retention(AnnotationRetention.RUNTIME) @Scope annotation class MediaProjectionAppSelectorScope
+
+@Module(subcomponents = [MediaProjectionAppSelectorComponent::class])
+interface MediaProjectionModule {
+    @Binds
+    @IntoMap
+    @ClassKey(MediaProjectionAppSelectorActivity::class)
+    fun provideMediaProjectionAppSelectorActivity(
+        activity: MediaProjectionAppSelectorActivity
+    ): Activity
+}
+
+/** Scoped values for [MediaProjectionAppSelectorComponent].
+ *  We create a scope for the activity so certain dependencies like [TaskPreviewSizeProvider]
+ *  could be reused. */
+@Module
+interface MediaProjectionAppSelectorModule {
+
+    @Binds
+    @MediaProjectionAppSelectorScope
+    fun bindRecentTaskThumbnailLoader(
+        impl: ActivityTaskManagerThumbnailLoader
+    ): RecentTaskThumbnailLoader
+
+    @Binds
+    @MediaProjectionAppSelectorScope
+    fun bindRecentTaskListProvider(impl: ShellRecentTaskListProvider): RecentTaskListProvider
+
+    @Binds
+    @MediaProjectionAppSelectorScope
+    fun bindAppIconLoader(impl: IconLoaderLibAppIconLoader): AppIconLoader
+
+    companion object {
+        @Provides
+        @MediaProjectionAppSelector
+        @MediaProjectionAppSelectorScope
+        fun provideAppSelectorComponentName(context: Context): ComponentName =
+                ComponentName(context, MediaProjectionAppSelectorActivity::class.java)
+
+        @Provides
+        @MediaProjectionAppSelector
+        @MediaProjectionAppSelectorScope
+        fun bindConfigurationController(
+            activity: MediaProjectionAppSelectorActivity
+        ): ConfigurationController = ConfigurationControllerImpl(activity)
+
+        @Provides
+        @MediaProjectionAppSelector
+        @MediaProjectionAppSelectorScope
+        fun provideCoroutineScope(@Application applicationScope: CoroutineScope): CoroutineScope =
+            CoroutineScope(applicationScope.coroutineContext + SupervisorJob())
+    }
+}
+
+@Subcomponent(modules = [MediaProjectionAppSelectorModule::class])
+@MediaProjectionAppSelectorScope
+interface MediaProjectionAppSelectorComponent {
+
+    /** Generates [MediaProjectionAppSelectorComponent]. */
+    @Subcomponent.Factory
+    interface Factory {
+        /**
+         * Create a factory to inject the activity into the graph
+         */
+        fun create(
+            @BindsInstance activity: MediaProjectionAppSelectorActivity,
+            @BindsInstance view: MediaProjectionAppSelectorView,
+            @BindsInstance resultHandler: MediaProjectionAppSelectorResultHandler,
+        ): MediaProjectionAppSelectorComponent
+    }
+
+    val controller: MediaProjectionAppSelectorController
+    val recentsViewController: MediaProjectionRecentsViewController
+
+    @MediaProjectionAppSelector val configurationController: ConfigurationController
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
index 59c6635..d744a40b 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorController.kt
@@ -17,20 +17,22 @@
 package com.android.systemui.mediaprojection.appselector
 
 import android.content.ComponentName
-import com.android.systemui.media.dagger.MediaProjectionAppSelector
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.data.RecentTaskListProvider
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.launch
+import javax.inject.Inject
 
-class MediaProjectionAppSelectorController(
+@MediaProjectionAppSelectorScope
+class MediaProjectionAppSelectorController @Inject constructor(
     private val recentTaskListProvider: RecentTaskListProvider,
+    private val view: MediaProjectionAppSelectorView,
     @MediaProjectionAppSelector private val scope: CoroutineScope,
-    private val appSelectorComponentName: ComponentName
+    @MediaProjectionAppSelector private val appSelectorComponentName: ComponentName
 ) {
 
-    fun init(view: MediaProjectionAppSelectorView) {
+    fun init() {
         scope.launch {
             val tasks = recentTaskListProvider.loadRecentTasks().sortTasks()
             view.bind(tasks)
@@ -42,7 +44,7 @@
     }
 
     private fun List<RecentTask>.sortTasks(): List<RecentTask> =
-        asReversed().sortedBy {
+        sortedBy {
             // Show normal tasks first and only then tasks with opened app selector
             it.topActivityComponent == appSelectorComponentName
         }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
new file mode 100644
index 0000000..93c3bce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorResultHandler.kt
@@ -0,0 +1,15 @@
+package com.android.systemui.mediaprojection.appselector
+
+import android.os.IBinder
+
+/**
+ * Interface that allows to continue the media projection flow and return the selected app
+ * result to the original caller.
+ */
+interface MediaProjectionAppSelectorResultHandler {
+    /**
+     * Return selected app to the original caller of the media projection app picker.
+     * @param launchCookie launch cookie of the launched activity of the target app
+     */
+    fun returnSelectedApp(launchCookie: IBinder)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt
index 0bdddfe..0927f3b 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/AppIconLoader.kt
@@ -17,11 +17,17 @@
 package com.android.systemui.mediaprojection.appselector.data
 
 import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ComponentInfoFlags
 import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import com.android.launcher3.icons.BaseIconFactory.IconOptions
+import com.android.launcher3.icons.IconFactory
 import com.android.systemui.dagger.qualifiers.Background
+import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.withContext
-import javax.inject.Inject
 
 interface AppIconLoader {
     suspend fun loadIcon(userId: Int, component: ComponentName): Drawable?
@@ -31,11 +37,20 @@
 @Inject
 constructor(
     @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val context: Context,
+    private val packageManager: PackageManager
 ) : AppIconLoader {
 
     override suspend fun loadIcon(userId: Int, component: ComponentName): Drawable? =
         withContext(backgroundDispatcher) {
-            // TODO(b/240924731): add a blocking call to load an icon using iconloaderlib
-            null
+            IconFactory.obtain(context).use<IconFactory, Drawable?> { iconFactory ->
+                val activityInfo = packageManager
+                        .getActivityInfo(component, ComponentInfoFlags.of(0))
+                val icon = activityInfo.loadIcon(packageManager) ?: return@withContext null
+                val userHandler = UserHandle.of(userId)
+                val options = IconOptions().apply { setUser(userHandler) }
+                val badgedIcon = iconFactory.createBadgedIconBitmap(icon, options)
+                badgedIcon.newIcon(context)
+            }
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
index 6d67e28..cd994b8 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTask.kt
@@ -16,11 +16,13 @@
 
 package com.android.systemui.mediaprojection.appselector.data
 
+import android.annotation.ColorInt
 import android.content.ComponentName
 
 data class RecentTask(
     val taskId: Int,
     val userId: Int,
     val topActivityComponent: ComponentName?,
-    val baseIntentComponent: ComponentName?
+    val baseIntentComponent: ComponentName?,
+    @ColorInt val colorBackground: Int?
 )
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
index 5a09435..e8b49cd 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskListProvider.kt
@@ -16,23 +16,61 @@
 
 package com.android.systemui.mediaprojection.appselector.data
 
+import android.app.ActivityManager
+import android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.kotlin.getOrNull
+import com.android.wm.shell.recents.RecentTasks
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import java.util.Optional
+import javax.inject.Inject
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.withContext
-import javax.inject.Inject
+import java.util.concurrent.Executor
 
 interface RecentTaskListProvider {
+    /** Loads recent tasks, the returned task list is from the most-recent to least-recent order */
     suspend fun loadRecentTasks(): List<RecentTask>
 }
 
 class ShellRecentTaskListProvider
 @Inject
-constructor(@Background private val coroutineDispatcher: CoroutineDispatcher) :
-    RecentTaskListProvider {
+constructor(
+    @Background private val coroutineDispatcher: CoroutineDispatcher,
+    @Background private val backgroundExecutor: Executor,
+    private val recentTasks: Optional<RecentTasks>
+) : RecentTaskListProvider {
+
+    private val recents by lazy { recentTasks.getOrNull() }
 
     override suspend fun loadRecentTasks(): List<RecentTask> =
         withContext(coroutineDispatcher) {
-            // TODO(b/240924731): add blocking call to load the recents
-            emptyList()
+            val rawRecentTasks: List<GroupedRecentTaskInfo> = recents?.getTasks() ?: emptyList()
+
+            rawRecentTasks
+                .flatMap { listOfNotNull(it.taskInfo1, it.taskInfo2) }
+                .map {
+                    RecentTask(
+                        it.taskId,
+                        it.userId,
+                        it.topActivity,
+                        it.baseIntent?.component,
+                        it.taskDescription?.backgroundColor
+                    )
+                }
+        }
+
+    private suspend fun RecentTasks.getTasks(): List<GroupedRecentTaskInfo> =
+        suspendCoroutine { continuation ->
+            getRecentTasks(
+                Integer.MAX_VALUE,
+                RECENT_IGNORE_UNAVAILABLE,
+                ActivityManager.getCurrentUser(),
+                backgroundExecutor
+            ) { tasks ->
+                continuation.resume(tasks)
+            }
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt
index 4291280..47faaed 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/data/RecentTaskThumbnailLoader.kt
@@ -18,6 +18,7 @@
 
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.system.ActivityManagerWrapper
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.withContext
@@ -30,12 +31,13 @@
 @Inject
 constructor(
     @Background private val coroutineDispatcher: CoroutineDispatcher,
-) :
-    RecentTaskThumbnailLoader {
+    private val activityManager: ActivityManagerWrapper
+) : RecentTaskThumbnailLoader {
 
     override suspend fun loadThumbnail(taskId: Int): ThumbnailData? =
         withContext(coroutineDispatcher) {
-            // TODO(b/240924731): add blocking call to load a thumbnail
-             null
+            val thumbnailData =
+                activityManager.getTaskThumbnail(taskId, /* isLowResolution= */ false)
+            if (thumbnailData.thumbnail == null) null else thumbnailData
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
new file mode 100644
index 0000000..c816446
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionRecentsViewController.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.appselector.view
+
+import android.app.ActivityOptions
+import android.app.IActivityTaskManager
+import android.graphics.Rect
+import android.os.Binder
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.R
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorResultHandler
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope
+import com.android.systemui.mediaprojection.appselector.data.RecentTask
+import com.android.systemui.mediaprojection.appselector.view.RecentTasksAdapter.RecentTaskClickListener
+import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
+import com.android.systemui.util.recycler.HorizontalSpacerItemDecoration
+import javax.inject.Inject
+
+/**
+ * Controller that handles view of the recent apps selector in the media projection activity.
+ * It is responsible for creating and updating recent apps view.
+ */
+@MediaProjectionAppSelectorScope
+class MediaProjectionRecentsViewController
+@Inject
+constructor(
+    private val recentTasksAdapterFactory: RecentTasksAdapter.Factory,
+    private val taskViewSizeProvider: TaskPreviewSizeProvider,
+    private val activityTaskManager: IActivityTaskManager,
+    private val resultHandler: MediaProjectionAppSelectorResultHandler,
+) : RecentTaskClickListener, TaskPreviewSizeListener {
+
+    private var views: Views? = null
+    private var lastBoundData: List<RecentTask>? = null
+
+    init {
+        taskViewSizeProvider.addCallback(this)
+    }
+
+    fun createView(parent: ViewGroup): ViewGroup =
+        views?.root ?: createRecentViews(parent).also {
+            views = it
+            lastBoundData?.let { recents -> bind(recents) }
+        }.root
+
+    fun bind(recentTasks: List<RecentTask>) {
+        views?.apply {
+            if (recentTasks.isEmpty()) {
+                root.visibility = View.GONE
+                return
+            }
+
+            progress.visibility = View.GONE
+            recycler.visibility = View.VISIBLE
+            root.visibility = View.VISIBLE
+
+            recycler.adapter =
+                recentTasksAdapterFactory.create(
+                    recentTasks,
+                    this@MediaProjectionRecentsViewController
+                )
+        }
+
+        lastBoundData = recentTasks
+    }
+
+    private fun createRecentViews(parent: ViewGroup): Views {
+        val recentsRoot =
+            LayoutInflater.from(parent.context)
+                .inflate(R.layout.media_projection_recent_tasks, parent, /* attachToRoot= */ false)
+                as ViewGroup
+
+        val container = recentsRoot.findViewById<View>(R.id.media_projection_recent_tasks_container)
+        container.setTaskHeightSize()
+
+        val progress = recentsRoot.requireViewById<View>(R.id.media_projection_recent_tasks_loader)
+        val recycler =
+            recentsRoot.requireViewById<RecyclerView>(R.id.media_projection_recent_tasks_recycler)
+        recycler.layoutManager =
+            LinearLayoutManager(
+                parent.context,
+                LinearLayoutManager.HORIZONTAL,
+                /* reverseLayout= */ false
+            )
+
+        val itemDecoration =
+            HorizontalSpacerItemDecoration(
+                parent.resources.getDimensionPixelOffset(
+                    R.dimen.media_projection_app_selector_recents_padding
+                )
+            )
+        recycler.addItemDecoration(itemDecoration)
+
+        return Views(recentsRoot, container, progress, recycler)
+    }
+
+    override fun onRecentAppClicked(task: RecentTask, view: View) {
+        val launchCookie = Binder()
+        val activityOptions =
+            ActivityOptions.makeScaleUpAnimation(
+                view,
+                /* startX= */ 0,
+                /* startY= */ 0,
+                view.width,
+                view.height
+            )
+        activityOptions.launchCookie = launchCookie
+
+        activityTaskManager.startActivityFromRecents(task.taskId, activityOptions.toBundle())
+        resultHandler.returnSelectedApp(launchCookie)
+    }
+
+    override fun onTaskSizeChanged(size: Rect) {
+        views?.recentsContainer?.setTaskHeightSize()
+    }
+
+    private fun View.setTaskHeightSize() {
+        val thumbnailHeight = taskViewSizeProvider.size.height()
+        val itemHeight =
+            thumbnailHeight +
+                context.resources.getDimensionPixelSize(
+                    R.dimen.media_projection_app_selector_task_icon_size
+                ) +
+                context.resources.getDimensionPixelSize(
+                    R.dimen.media_projection_app_selector_task_icon_margin
+                ) * 2
+
+        layoutParams = layoutParams.apply { height = itemHeight }
+    }
+
+    private class Views(
+        val root: ViewGroup,
+        val recentsContainer: View,
+        val progress: View,
+        val recycler: RecyclerView
+    )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
new file mode 100644
index 0000000..b682bd1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/MediaProjectionTaskView.kt
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.appselector.view
+
+import android.content.Context
+import android.graphics.BitmapShader
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Shader
+import android.util.AttributeSet
+import android.view.View
+import android.view.WindowManager
+import androidx.core.content.getSystemService
+import androidx.core.content.res.use
+import com.android.internal.R as AndroidR
+import com.android.systemui.R
+import com.android.systemui.mediaprojection.appselector.data.RecentTask
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
+import com.android.systemui.shared.recents.utilities.Utilities.isTablet
+
+/**
+ * Custom view that shows a thumbnail preview of one recent task based on [ThumbnailData].
+ * It handles proper cropping and positioning of the thumbnail using [PreviewPositionHelper].
+ */
+class MediaProjectionTaskView
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+    View(context, attrs, defStyleAttr) {
+
+    private val defaultBackgroundColor: Int
+
+    init {
+        val backgroundColorAttribute = intArrayOf(android.R.attr.colorBackgroundFloating)
+        defaultBackgroundColor =
+            context.obtainStyledAttributes(backgroundColorAttribute).use {
+                it.getColor(/* index= */ 0, /* defValue= */ Color.BLACK)
+            }
+    }
+
+    private val windowManager: WindowManager = context.getSystemService()!!
+    private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
+    private val backgroundPaint =
+        Paint(Paint.ANTI_ALIAS_FLAG).apply { color = defaultBackgroundColor }
+    private val cornerRadius =
+        context.resources.getDimensionPixelSize(
+            R.dimen.media_projection_app_selector_task_rounded_corners
+        )
+    private val previewPositionHelper = PreviewPositionHelper()
+    private val previewRect = Rect()
+
+    private var task: RecentTask? = null
+    private var thumbnailData: ThumbnailData? = null
+
+    private var bitmapShader: BitmapShader? = null
+
+    fun bindTask(task: RecentTask?, thumbnailData: ThumbnailData?) {
+        this.task = task
+        this.thumbnailData = thumbnailData
+
+        // Strip alpha channel to make sure that the color is not semi-transparent
+        val color = (task?.colorBackground ?: Color.BLACK) or 0xFF000000.toInt()
+
+        paint.color = color
+        backgroundPaint.color = color
+
+        refresh()
+    }
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        updateThumbnailMatrix()
+        invalidate()
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        // Always draw the background since the snapshots might be translucent or partially empty
+        // (For example, tasks been reparented out of dismissing split root when drag-to-dismiss
+        // split screen).
+        canvas.drawRoundRect(
+            0f,
+            1f,
+            width.toFloat(),
+            (height - 1).toFloat(),
+            cornerRadius.toFloat(),
+            cornerRadius.toFloat(),
+            backgroundPaint
+        )
+
+        val drawBackgroundOnly = task == null || bitmapShader == null || thumbnailData == null
+        if (drawBackgroundOnly) {
+            return
+        }
+
+        // Draw the task thumbnail using bitmap shader in the paint
+        canvas.drawRoundRect(
+            0f,
+            0f,
+            width.toFloat(),
+            height.toFloat(),
+            cornerRadius.toFloat(),
+            cornerRadius.toFloat(),
+            paint
+        )
+    }
+
+    private fun refresh() {
+        val thumbnailBitmap = thumbnailData?.thumbnail
+
+        if (thumbnailBitmap != null) {
+            thumbnailBitmap.prepareToDraw()
+            bitmapShader =
+                BitmapShader(thumbnailBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
+            paint.shader = bitmapShader
+            updateThumbnailMatrix()
+        } else {
+            bitmapShader = null
+            paint.shader = null
+        }
+
+        invalidate()
+    }
+
+    private fun updateThumbnailMatrix() {
+        previewPositionHelper.isOrientationChanged = false
+
+        val bitmapShader = bitmapShader ?: return
+        val thumbnailData = thumbnailData ?: return
+        val display = context.display ?: return
+        val windowMetrics = windowManager.maximumWindowMetrics
+
+        previewRect.set(0, 0, thumbnailData.thumbnail.width, thumbnailData.thumbnail.height)
+
+        val currentRotation: Int = display.rotation
+        val displayWidthPx = windowMetrics.bounds.width()
+        val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
+        val isTablet = isTablet(context)
+        val taskbarSize =
+            if (isTablet) {
+                resources.getDimensionPixelSize(AndroidR.dimen.taskbar_frame_height)
+            } else {
+                0
+            }
+
+        previewPositionHelper.updateThumbnailMatrix(
+            previewRect,
+            thumbnailData,
+            measuredWidth,
+            measuredHeight,
+            displayWidthPx,
+            taskbarSize,
+            isTablet,
+            currentRotation,
+            isRtl
+        )
+
+        bitmapShader.setLocalMatrix(previewPositionHelper.matrix)
+        paint.shader = bitmapShader
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
index ec5abc7..15cfeee 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTaskViewHolder.kt
@@ -16,15 +16,17 @@
 
 package com.android.systemui.mediaprojection.appselector.view
 
+import android.graphics.Rect
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import androidx.recyclerview.widget.RecyclerView
 import com.android.systemui.R
-import com.android.systemui.media.dagger.MediaProjectionAppSelector
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelector
 import com.android.systemui.mediaprojection.appselector.data.AppIconLoader
 import com.android.systemui.mediaprojection.appselector.data.RecentTask
 import com.android.systemui.mediaprojection.appselector.data.RecentTaskThumbnailLoader
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -32,19 +34,27 @@
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.launch
 
-class RecentTaskViewHolder @AssistedInject constructor(
-    @Assisted root: ViewGroup,
+class RecentTaskViewHolder
+@AssistedInject
+constructor(
+    @Assisted private val root: ViewGroup,
     private val iconLoader: AppIconLoader,
     private val thumbnailLoader: RecentTaskThumbnailLoader,
+    private val taskViewSizeProvider: TaskPreviewSizeProvider,
     @MediaProjectionAppSelector private val scope: CoroutineScope
-) : RecyclerView.ViewHolder(root) {
+) : RecyclerView.ViewHolder(root), ConfigurationListener, TaskPreviewSizeProvider.TaskPreviewSizeListener {
 
+    val thumbnailView: MediaProjectionTaskView = root.requireViewById(R.id.task_thumbnail)
     private val iconView: ImageView = root.requireViewById(R.id.task_icon)
-    private val thumbnailView: ImageView = root.requireViewById(R.id.task_thumbnail)
 
     private var job: Job? = null
 
+    init {
+        updateThumbnailSize()
+    }
+
     fun bind(task: RecentTask, onClick: (View) -> Unit) {
+        taskViewSizeProvider.addCallback(this)
         job?.cancel()
 
         job =
@@ -57,20 +67,33 @@
                 }
                 launch {
                     val thumbnail = thumbnailLoader.loadThumbnail(task.taskId)
-                    thumbnailView.setImageBitmap(thumbnail?.thumbnail)
+                    thumbnailView.bindTask(task, thumbnail)
                 }
             }
 
-        thumbnailView.setOnClickListener(onClick)
+        root.setOnClickListener(onClick)
     }
 
     fun onRecycled() {
+        taskViewSizeProvider.removeCallback(this)
         iconView.setImageDrawable(null)
-        thumbnailView.setImageBitmap(null)
+        thumbnailView.bindTask(null, null)
         job?.cancel()
         job = null
     }
 
+    override fun onTaskSizeChanged(size: Rect) {
+        updateThumbnailSize()
+    }
+
+    private fun updateThumbnailSize() {
+        thumbnailView.layoutParams =
+                thumbnailView.layoutParams.apply {
+                    width = taskViewSizeProvider.size.width()
+                    height = taskViewSizeProvider.size.height()
+                }
+    }
+
     @AssistedFactory
     fun interface Factory {
         fun create(root: ViewGroup): RecentTaskViewHolder
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt
index ec9cfa8..6af50a0 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/RecentTasksAdapter.kt
@@ -26,7 +26,9 @@
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 
-class RecentTasksAdapter @AssistedInject constructor(
+class RecentTasksAdapter
+@AssistedInject
+constructor(
     @Assisted private val items: List<RecentTask>,
     @Assisted private val listener: RecentTaskClickListener,
     private val viewHolderFactory: RecentTaskViewHolder.Factory
@@ -34,8 +36,8 @@
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecentTaskViewHolder {
         val taskItem =
-            LayoutInflater.from(parent.context)
-                .inflate(R.layout.media_projection_task_item, null) as ViewGroup
+                LayoutInflater.from(parent.context)
+                        .inflate(R.layout.media_projection_task_item, parent, false) as ViewGroup
 
         return viewHolderFactory.create(taskItem)
     }
@@ -43,7 +45,7 @@
     override fun onBindViewHolder(holder: RecentTaskViewHolder, position: Int) {
         val task = items[position]
         holder.bind(task, onClick = {
-            listener.onRecentClicked(task, holder.itemView)
+            listener.onRecentAppClicked(task, holder.itemView)
         })
     }
 
@@ -54,7 +56,7 @@
     }
 
     interface RecentTaskClickListener {
-        fun onRecentClicked(task: RecentTask, view: View)
+        fun onRecentAppClicked(task: RecentTask, view: View)
     }
 
     @AssistedFactory
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
new file mode 100644
index 0000000..88d5eaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProvider.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.mediaprojection.appselector.view
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Rect
+import android.view.WindowManager
+import com.android.internal.R as AndroidR
+import com.android.systemui.mediaprojection.appselector.MediaProjectionAppSelectorScope
+import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
+import com.android.systemui.shared.recents.utilities.Utilities.isTablet
+import com.android.systemui.statusbar.policy.CallbackController
+import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
+import javax.inject.Inject
+
+@MediaProjectionAppSelectorScope
+class TaskPreviewSizeProvider
+@Inject
+constructor(
+    private val context: Context,
+    private val windowManager: WindowManager,
+    configurationController: ConfigurationController
+) : CallbackController<TaskPreviewSizeListener>, ConfigurationListener {
+
+    /** Returns the size of the task preview on the screen in pixels */
+    val size: Rect = calculateSize()
+
+    private val listeners = arrayListOf<TaskPreviewSizeListener>()
+
+    init {
+        configurationController.addCallback(this)
+    }
+
+    override fun onConfigChanged(newConfig: Configuration) {
+        val newSize = calculateSize()
+        if (newSize != size) {
+            size.set(newSize)
+            listeners.forEach { it.onTaskSizeChanged(size) }
+        }
+    }
+
+    private fun calculateSize(): Rect {
+        val windowMetrics = windowManager.maximumWindowMetrics
+        val maximumWindowHeight = windowMetrics.bounds.height()
+        val width = windowMetrics.bounds.width()
+        var height = maximumWindowHeight
+
+        val isTablet = isTablet(context)
+        if (isTablet) {
+            val taskbarSize =
+                context.resources.getDimensionPixelSize(AndroidR.dimen.taskbar_frame_height)
+            height -= taskbarSize
+        }
+
+        val previewSize = Rect(0, 0, width, height)
+        val scale = (height / maximumWindowHeight.toFloat()) / SCREEN_HEIGHT_TO_TASK_HEIGHT_RATIO
+        previewSize.scale(scale)
+
+        return previewSize
+    }
+
+    override fun addCallback(listener: TaskPreviewSizeListener) {
+        listeners += listener
+    }
+
+    override fun removeCallback(listener: TaskPreviewSizeListener) {
+        listeners -= listener
+    }
+
+    interface TaskPreviewSizeListener {
+        fun onTaskSizeChanged(size: Rect)
+    }
+}
+
+/**
+ * How many times smaller the task preview should be on the screen comparing to the height of the
+ * screen
+ */
+private const val SCREEN_HEIGHT_TO_TASK_HEIGHT_RATIO = 4f
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 30947e8..50a10bc 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -541,10 +541,12 @@
                 if (!mImeVisible) {
                     // IME not showing, take all touches
                     info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+                    return;
                 }
                 if (!mView.isImeRenderingNavButtons()) {
                     // IME showing but not drawing any buttons, take all touches
                     info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
+                    return;
                 }
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
index 3789cbb..029cf68 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarController.java
@@ -142,6 +142,9 @@
         boolean isOldConfigTablet = mIsTablet;
         mIsTablet = isTablet(mContext);
         boolean largeScreenChanged = mIsTablet != isOldConfigTablet;
+        if (mTaskbarDelegate.isInitialized()) {
+            mTaskbarDelegate.onConfigurationChanged(newConfig);
+        }
         // If we folded/unfolded while in 3 button, show navbar in folded state, hide in unfolded
         if (largeScreenChanged && updateNavbarForTaskbar()) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 9e0c496..73fc21e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -40,7 +40,6 @@
 
 import android.app.StatusBarManager;
 import android.app.StatusBarManager.WindowVisibleState;
-import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -87,7 +86,7 @@
 @SysUISingleton
 public class TaskbarDelegate implements CommandQueue.Callbacks,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
-        ComponentCallbacks, Dumpable {
+        Dumpable {
     private static final String TAG = TaskbarDelegate.class.getSimpleName();
 
     private final EdgeBackGestureHandler mEdgeBackGestureHandler;
@@ -225,7 +224,6 @@
         // Initialize component callback
         Display display = mDisplayManager.getDisplay(displayId);
         mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
-        mWindowContext.registerComponentCallbacks(this);
         mScreenPinningNotify = new ScreenPinningNotify(mWindowContext);
         // Set initial state for any listeners
         updateSysuiFlags();
@@ -233,6 +231,7 @@
         mLightBarController.setNavigationBar(mLightBarTransitionsController);
         mPipOptional.ifPresent(this::addPipExclusionBoundsChangeListener);
         mEdgeBackGestureHandler.setBackAnimation(mBackAnimation);
+        mEdgeBackGestureHandler.onConfigurationChanged(mContext.getResources().getConfiguration());
         mInitialized = true;
     }
 
@@ -247,10 +246,7 @@
         mNavBarHelper.destroy();
         mEdgeBackGestureHandler.onNavBarDetached();
         mScreenPinningNotify = null;
-        if (mWindowContext != null) {
-            mWindowContext.unregisterComponentCallbacks(this);
-            mWindowContext = null;
-        }
+        mWindowContext = null;
         mAutoHideController.setNavigationBar(null);
         mLightBarTransitionsController.destroy();
         mLightBarController.setNavigationBar(null);
@@ -267,8 +263,9 @@
     }
 
     /**
-     * Returns {@code true} if this taskBar is {@link #init(int)}. Returns {@code false} if this
-     * taskbar has not yet been {@link #init(int)} or has been {@link #destroy()}.
+     * Returns {@code true} if this taskBar is {@link #init(int)}.
+     * Returns {@code false} if this taskbar has not yet been {@link #init(int)}
+     * or has been {@link #destroy()}.
      */
     public boolean isInitialized() {
         return mInitialized;
@@ -460,15 +457,11 @@
         return mBehavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
     }
 
-    @Override
     public void onConfigurationChanged(Configuration configuration) {
         mEdgeBackGestureHandler.onConfigurationChanged(configuration);
     }
 
     @Override
-    public void onLowMemory() {}
-
-    @Override
     public void showPinningEnterExitToast(boolean entering) {
         updateSysuiFlags();
         if (mScreenPinningNotify == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index d605c1a..a8799c7 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -19,6 +19,7 @@
 
 import static com.android.systemui.classifier.Classifier.BACK_GESTURE;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -57,7 +58,6 @@
 
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.policy.GestureNavigationSettingsObserver;
-import com.android.internal.util.LatencyTracker;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -199,7 +199,7 @@
     private final Rect mNavBarOverlayExcludedBounds = new Rect();
     private final Region mExcludeRegion = new Region();
     private final Region mUnrestrictedExcludeRegion = new Region();
-    private final LatencyTracker mLatencyTracker;
+    private final Provider<NavigationBarEdgePanel> mNavBarEdgePanelProvider;
     private final Provider<BackGestureTfClassifierProvider>
             mBackGestureTfClassifierProviderProvider;
     private final FeatureFlags mFeatureFlags;
@@ -303,6 +303,13 @@
                     mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x,
                             (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
                 }
+
+                @Override
+                public void setTriggerBack(boolean triggerBack) {
+                    if (mBackAnimation != null) {
+                        mBackAnimation.setTriggerBack(triggerBack);
+                    }
+                }
             };
 
     private final SysUiState.SysUiStateCallback mSysUiStateCallback =
@@ -332,7 +339,7 @@
             IWindowManager windowManagerService,
             Optional<Pip> pipOptional,
             FalsingManager falsingManager,
-            LatencyTracker latencyTracker,
+            Provider<NavigationBarEdgePanel> navigationBarEdgePanelProvider,
             Provider<BackGestureTfClassifierProvider> backGestureTfClassifierProviderProvider,
             FeatureFlags featureFlags) {
         super(broadcastDispatcher);
@@ -351,7 +358,7 @@
         mWindowManagerService = windowManagerService;
         mPipOptional = pipOptional;
         mFalsingManager = falsingManager;
-        mLatencyTracker = latencyTracker;
+        mNavBarEdgePanelProvider = navigationBarEdgePanelProvider;
         mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider;
         mFeatureFlags = featureFlags;
         mLastReportedConfig.setTo(mContext.getResources().getConfiguration());
@@ -576,8 +583,7 @@
             setEdgeBackPlugin(
                     mBackPanelControllerFactory.create(mContext));
         } else {
-            setEdgeBackPlugin(
-                    new NavigationBarEdgePanel(mContext, mLatencyTracker));
+            setEdgeBackPlugin(mNavBarEdgePanelProvider.get());
         }
     }
 
@@ -950,7 +956,7 @@
                 mStartingQuickstepRotation != rotation;
     }
 
-    public void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigurationChanged(@NonNull Configuration newConfig) {
         if (mStartingQuickstepRotation > -1) {
             updateDisabledForQuickstep(newConfig);
         }
@@ -1084,7 +1090,7 @@
         private final IWindowManager mWindowManagerService;
         private final Optional<Pip> mPipOptional;
         private final FalsingManager mFalsingManager;
-        private final LatencyTracker mLatencyTracker;
+        private final Provider<NavigationBarEdgePanel> mNavBarEdgePanelProvider;
         private final Provider<BackGestureTfClassifierProvider>
                 mBackGestureTfClassifierProviderProvider;
         private final FeatureFlags mFeatureFlags;
@@ -1104,7 +1110,7 @@
                        IWindowManager windowManagerService,
                        Optional<Pip> pipOptional,
                        FalsingManager falsingManager,
-                       LatencyTracker latencyTracker,
+                       Provider<NavigationBarEdgePanel> navBarEdgePanelProvider,
                        Provider<BackGestureTfClassifierProvider>
                                backGestureTfClassifierProviderProvider,
                        FeatureFlags featureFlags) {
@@ -1122,7 +1128,7 @@
             mWindowManagerService = windowManagerService;
             mPipOptional = pipOptional;
             mFalsingManager = falsingManager;
-            mLatencyTracker = latencyTracker;
+            mNavBarEdgePanelProvider = navBarEdgePanelProvider;
             mBackGestureTfClassifierProviderProvider = backGestureTfClassifierProviderProvider;
             mFeatureFlags = featureFlags;
         }
@@ -1145,7 +1151,7 @@
                     mWindowManagerService,
                     mPipOptional,
                     mFalsingManager,
-                    mLatencyTracker,
+                    mNavBarEdgePanelProvider,
                     mBackGestureTfClassifierProviderProvider,
                     mFeatureFlags);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 122852f..1230708 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -52,9 +52,9 @@
 
 import com.android.internal.util.LatencyTracker;
 import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.plugins.NavigationEdgeBackPlugin;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 import com.android.systemui.statusbar.VibratorHelper;
@@ -62,6 +62,8 @@
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+
 public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPlugin {
 
     private static final String TAG = "NavigationBarEdgePanel";
@@ -282,11 +284,16 @@
             };
     private BackCallback mBackCallback;
 
-    public NavigationBarEdgePanel(Context context, LatencyTracker latencyTracker) {
+    @Inject
+    public NavigationBarEdgePanel(
+            Context context,
+            LatencyTracker latencyTracker,
+            VibratorHelper vibratorHelper,
+            @Background Executor backgroundExecutor) {
         super(context);
 
         mWindowManager = context.getSystemService(WindowManager.class);
-        mVibratorHelper = Dependency.get(VibratorHelper.class);
+        mVibratorHelper = vibratorHelper;
 
         mDensity = context.getResources().getDisplayMetrics().density;
 
@@ -358,7 +365,6 @@
 
         setVisibility(GONE);
 
-        Executor backgroundExecutor = Dependency.get(Dependency.BACKGROUND_EXECUTOR);
         boolean isPrimaryDisplay = mContext.getDisplayId() == DEFAULT_DISPLAY;
         mRegionSamplingHelper = new RegionSamplingHelper(this,
                 new RegionSamplingHelper.SamplingCallback() {
@@ -880,6 +886,7 @@
             // Whenever the trigger back state changes the existing translation animation should be
             // cancelled
             mTranslationAnimation.cancel();
+            mBackCallback.setTriggerBack(mTriggerBack);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 7b27cf4..1ef6426 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -60,6 +60,7 @@
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -82,7 +83,7 @@
     private static final String EXTRA_VISIBLE = "visible";
 
     private final Rect mQsBounds = new Rect();
-    private final StatusBarStateController mStatusBarStateController;
+    private final SysuiStatusBarStateController mStatusBarStateController;
     private final FalsingManager mFalsingManager;
     private final KeyguardBypassController mBypassController;
     private boolean mQsExpanded;
@@ -159,7 +160,7 @@
      * Progress of pull down from the center of the lock screen.
      * @see com.android.systemui.statusbar.LockscreenShadeTransitionController
      */
-    private float mFullShadeProgress;
+    private float mLockscreenToShadeProgress;
 
     private boolean mOverScrolling;
 
@@ -177,7 +178,7 @@
     @Inject
     public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
             QSTileHost qsTileHost,
-            StatusBarStateController statusBarStateController, CommandQueue commandQueue,
+            SysuiStatusBarStateController statusBarStateController, CommandQueue commandQueue,
             @Named(QS_PANEL) MediaHost qsMediaHost,
             @Named(QUICK_QS_PANEL) MediaHost qqsMediaHost,
             KeyguardBypassController keyguardBypassController,
@@ -442,20 +443,19 @@
     }
 
     private void updateQsState() {
-        final boolean expanded = mQsExpanded || mInSplitShade;
-        final boolean expandVisually = expanded || mStackScrollerOverscrolling
+        final boolean expandVisually = mQsExpanded || mStackScrollerOverscrolling
                 || mHeaderAnimating;
-        mQSPanelController.setExpanded(expanded);
+        mQSPanelController.setExpanded(mQsExpanded);
         boolean keyguardShowing = isKeyguardState();
-        mHeader.setVisibility((expanded || !keyguardShowing || mHeaderAnimating
+        mHeader.setVisibility((mQsExpanded || !keyguardShowing || mHeaderAnimating
                 || mShowCollapsedOnKeyguard)
                 ? View.VISIBLE
                 : View.INVISIBLE);
         mHeader.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
-                || (expanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
+                || (mQsExpanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
         boolean qsPanelVisible = !mQsDisabled && expandVisually;
-        boolean footerVisible = qsPanelVisible &&  (expanded || !keyguardShowing || mHeaderAnimating
-                || mShowCollapsedOnKeyguard);
+        boolean footerVisible = qsPanelVisible && (mQsExpanded || !keyguardShowing
+                || mHeaderAnimating || mShowCollapsedOnKeyguard);
         mFooter.setVisibility(footerVisible ? View.VISIBLE : View.INVISIBLE);
         if (mQSFooterActionController != null) {
             mQSFooterActionController.setVisible(footerVisible);
@@ -463,7 +463,7 @@
             mQSFooterActionsViewModel.onVisibilityChangeRequested(footerVisible);
         }
         mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
-                || (expanded && !mStackScrollerOverscrolling));
+                || (mQsExpanded && !mStackScrollerOverscrolling));
         mQSPanelController.setVisibility(qsPanelVisible ? View.VISIBLE : View.INVISIBLE);
         if (DEBUG) {
             Log.d(TAG, "Footer: " + footerVisible + ", QS Panel: " + qsPanelVisible);
@@ -586,7 +586,7 @@
             mTransitioningToFullShade = isTransitioningToFullShade;
             updateShowCollapsedOnKeyguard();
         }
-        mFullShadeProgress = qsTransitionFraction;
+        mLockscreenToShadeProgress = qsTransitionFraction;
         setQsExpansion(mLastQSExpansion, mLastPanelFraction, mLastHeaderTranslation,
                 isTransitioningToFullShade ? qsSquishinessFraction : mSquishinessFraction);
     }
@@ -710,10 +710,13 @@
         }
         if (mInSplitShade) {
             // Large screens in landscape.
-            if (mTransitioningToFullShade || isKeyguardState()) {
+            // Need to check upcoming state as for unlocked -> AOD transition current state is
+            // not updated yet, but we're transitioning and UI should already follow KEYGUARD state
+            if (mTransitioningToFullShade || mStatusBarStateController.getCurrentOrUpcomingState()
+                    == StatusBarState.KEYGUARD) {
                 // Always use "mFullShadeProgress" on keyguard, because
                 // "panelExpansionFractions" is always 1 on keyguard split shade.
-                return mFullShadeProgress;
+                return mLockscreenToShadeProgress;
             } else {
                 return panelExpansionFraction;
             }
@@ -722,7 +725,7 @@
         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;
+            return mLockscreenToShadeProgress;
         } else {
             return panelExpansionFraction;
         }
@@ -930,7 +933,7 @@
         indentingPw.println("mLastHeaderTranslation: " + mLastHeaderTranslation);
         indentingPw.println("mInSplitShade: " + mInSplitShade);
         indentingPw.println("mTransitioningToFullShade: " + mTransitioningToFullShade);
-        indentingPw.println("mFullShadeProgress: " + mFullShadeProgress);
+        indentingPw.println("mLockscreenToShadeProgress: " + mLockscreenToShadeProgress);
         indentingPw.println("mOverScrolling: " + mOverScrolling);
         indentingPw.println("isCustomizing: " + mQSCustomizerController.isCustomizing());
         View view = getView();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 184089f7..6517ff3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -105,6 +105,7 @@
     private final Rect mClippingRect = new Rect();
     private ViewGroup mMediaHostView;
     private boolean mShouldMoveMediaOnExpansion = true;
+    private boolean mUsingCombinedHeaders = false;
 
     public QSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -148,6 +149,10 @@
         }
     }
 
+    void setUsingCombinedHeaders(boolean usingCombinedHeaders) {
+        mUsingCombinedHeaders = usingCombinedHeaders;
+    }
+
     protected void setHorizontalContentContainerClipping() {
         mHorizontalContentContainer.setClipChildren(true);
         mHorizontalContentContainer.setClipToPadding(false);
@@ -371,7 +376,9 @@
 
     protected void updatePadding() {
         final Resources res = mContext.getResources();
-        int paddingTop = res.getDimensionPixelSize(R.dimen.qs_panel_padding_top);
+        int paddingTop = res.getDimensionPixelSize(
+                mUsingCombinedHeaders ? R.dimen.qs_panel_padding_top_combined_headers
+                        : R.dimen.qs_panel_padding_top);
         int paddingBottom = res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom);
         setPaddingRelative(getPaddingStart(),
                 paddingTop,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index f41b905..f6db775 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs;
 
 import static com.android.systemui.classifier.Classifier.QS_SWIPE_SIDE;
+import static com.android.systemui.flags.Flags.COMBINED_QS_HEADERS;
 import static com.android.systemui.media.dagger.MediaModule.QS_PANEL;
 import static com.android.systemui.qs.QSPanel.QS_SHOW_BRIGHTNESS;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
@@ -27,7 +28,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaCarouselController;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.media.MediaHostState;
@@ -76,14 +77,14 @@
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QS_PANEL) MediaHost mediaHost,
             QSTileRevealController.Factory qsTileRevealControllerFactory,
-            DumpManager dumpManager, MediaCarouselController mediaCarouselController,
-            MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
+            DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
             QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
             BrightnessSliderController.Factory brightnessSliderFactory,
             FalsingManager falsingManager,
-            StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+            StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            FeatureFlags featureFlags) {
         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
-                metricsLogger, uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
+                metricsLogger, uiEventLogger, qsLogger, dumpManager);
         mTunerService = tunerService;
         mQsCustomizerController = qsCustomizerController;
         mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
@@ -95,6 +96,7 @@
         mBrightnessController = brightnessControllerFactory.create(mBrightnessSliderController);
         mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+        mView.setUsingCombinedHeaders(featureFlags.isEnabled(COMBINED_QS_HEADERS));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index a5c60a4..2727c83 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -23,8 +23,8 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.res.Configuration;
+import android.content.res.Configuration.Orientation;
 import android.metrics.LogMaker;
-import android.util.Log;
 import android.view.View;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -32,7 +32,6 @@
 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;
@@ -71,12 +70,12 @@
     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;
 
     @Nullable
     private Consumer<Boolean> mMediaVisibilityChangedListener;
+    @Orientation
     private int mLastOrientation;
     private String mCachedSpecs = "";
     @Nullable
@@ -90,21 +89,16 @@
             new QSPanel.OnConfigurationChangedListener() {
                 @Override
                 public void onConfigurationChange(Configuration newConfig) {
+                    mQSLogger.logOnConfigurationChanged(
+                        /* lastOrientation= */ mLastOrientation,
+                        /* newOrientation= */ newConfig.orientation,
+                        /* containerName= */ mView.getDumpableTag());
+
                     mShouldUseSplitNotificationShade =
-                            LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
-                    // Logging to aid the investigation of b/216244185.
-                    Log.d(TAG,
-                            "onConfigurationChange: "
-                                    + "mShouldUseSplitNotificationShade="
-                                    + mShouldUseSplitNotificationShade + ", "
-                                    + "newConfig.windowConfiguration="
-                                    + newConfig.windowConfiguration);
-                    mQSLogger.logOnConfigurationChanged(mLastOrientation, newConfig.orientation,
-                            mView.getDumpableTag());
-                    if (newConfig.orientation != mLastOrientation) {
-                        mLastOrientation = newConfig.orientation;
-                        switchTileLayout(false);
-                    }
+                        LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
+                    mLastOrientation = newConfig.orientation;
+
+                    switchTileLayoutIfNeeded();
                     onConfigurationChanged();
                 }
             };
@@ -133,8 +127,7 @@
             MetricsLogger metricsLogger,
             UiEventLogger uiEventLogger,
             QSLogger qsLogger,
-            DumpManager dumpManager,
-            MediaCarouselController mediaCarouselController
+            DumpManager dumpManager
     ) {
         super(view);
         mHost = host;
@@ -147,7 +140,6 @@
         mDumpManager = dumpManager;
         mShouldUseSplitNotificationShade =
                 LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
-        mMediaCarouselController = mediaCarouselController;
     }
 
     @Override
@@ -165,7 +157,6 @@
 
     public void setSquishinessFraction(float squishinessFraction) {
         mView.setSquishinessFraction(squishinessFraction);
-        mMediaCarouselController.setSquishinessFraction(squishinessFraction);
     }
 
     @Override
@@ -339,6 +330,10 @@
         }
     }
 
+    private void switchTileLayoutIfNeeded() {
+        switchTileLayout(/* force= */ false);
+    }
+
     boolean switchTileLayout(boolean force) {
         /* Whether or not the panel currently contains a media player. */
         boolean horizontal = shouldUseHorizontalLayout();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index bd75c75..ae6ed20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -444,7 +444,7 @@
         mShouldUseSettingsButton.set(false);
         mBgHandler.post(() -> {
             String settingsButtonText = getSettingsButton();
-            final View dialogView = createDialogView();
+            final View dialogView = createDialogView(quickSettingsContext);
             mMainHandler.post(() -> {
                 mDialog = new SystemUIDialog(quickSettingsContext, 0);
                 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -469,14 +469,14 @@
     }
 
     @VisibleForTesting
-    View createDialogView() {
+    View createDialogView(Context quickSettingsContext) {
         if (mSecurityController.isParentalControlsEnabled()) {
             return createParentalControlsDialogView();
         }
-        return createOrganizationDialogView();
+        return createOrganizationDialogView(quickSettingsContext);
     }
 
-    private View createOrganizationDialogView() {
+    private View createOrganizationDialogView(Context quickSettingsContext) {
         final boolean isDeviceManaged = mSecurityController.isDeviceManaged();
         final boolean hasWorkProfile = mSecurityController.hasWorkProfile();
         final CharSequence deviceOwnerOrganization =
@@ -487,7 +487,7 @@
         final String vpnName = mSecurityController.getPrimaryVpnName();
         final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName();
 
-        View dialogView = LayoutInflater.from(mContext)
+        View dialogView = LayoutInflater.from(quickSettingsContext)
                 .inflate(R.layout.quick_settings_footer_dialog, null, false);
 
         // device management section
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 7ce0ad0..9739974 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -26,7 +26,6 @@
 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;
@@ -56,10 +55,10 @@
             @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
                     Provider<Boolean> usingCollapsedLandscapeMediaProvider,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-            DumpManager dumpManager, MediaCarouselController mediaCarouselController
+            DumpManager dumpManager
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
-                uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
+                uiEventLogger, qsLogger, dumpManager);
         mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 264edb1..84d7e65 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -410,9 +410,9 @@
         // If forceExpanded (we are opening QS from lockscreen), the animators have been set to
         // position = 1f.
         if (forceExpanded) {
-            setTranslationY(panelTranslationY);
+            setAlpha(expansionFraction);
         } else {
-            setTranslationY(0);
+            setAlpha(1);
         }
 
         mKeyguardExpansionFraction = keyguardExpansionFraction;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index b585961..ccaab1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.VariableDateViewController;
@@ -104,7 +105,7 @@
                 mView.requireViewById(R.id.date_clock)
         );
 
-        mIconManager = tintedIconManagerFactory.create(mIconContainer);
+        mIconManager = tintedIconManagerFactory.create(mIconContainer, StatusBarLocation.QS);
         mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
         mColorExtractor = colorExtractor;
         mOnColorsChangedListener = (extractor, which) -> {
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 28ddead..dd1ffcc 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
@@ -222,6 +222,7 @@
 
     private fun bindButton(button: IconButtonViewHolder, model: FooterActionsButtonViewModel?) {
         val buttonView = button.view
+        buttonView.id = model?.id ?: View.NO_ID
         buttonView.isVisible = model != null
         if (model == null) {
             return
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 2ad0513..9b5f683 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
@@ -25,6 +25,7 @@
  * power buttons.
  */
 data class FooterActionsButtonViewModel(
+    val id: Int,
     val icon: Icon,
     val iconTint: Int?,
     @DrawableRes val background: Int,
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 a935338..11d9555 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,6 +138,7 @@
     /** The model for the settings button. */
     val settings: FooterActionsButtonViewModel =
         FooterActionsButtonViewModel(
+            id = R.id.settings_button_container,
             Icon.Resource(
                 R.drawable.ic_settings,
                 ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
@@ -151,6 +152,7 @@
     val power: FooterActionsButtonViewModel? =
         if (showPowerButton) {
             FooterActionsButtonViewModel(
+                id = R.id.pm_lite,
                 Icon.Resource(
                     android.R.drawable.ic_lock_power_off,
                     ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
@@ -256,6 +258,7 @@
             }
 
         return FooterActionsButtonViewModel(
+            id = R.id.multi_user_switch,
             Icon.Loaded(
                 icon,
                 ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
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 97476b2..d2d5063 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -134,7 +134,7 @@
                 v.bind(name, drawable, item.info.id);
             }
             v.setActivated(item.isCurrent);
-            v.setDisabledByAdmin(mController.isDisabledByAdmin(item));
+            v.setDisabledByAdmin(item.isDisabledByAdmin());
             v.setEnabled(item.isSwitchToEnabled);
             UserSwitcherController.setSelectableAlpha(v);
 
@@ -173,16 +173,16 @@
             Trace.beginSection("UserDetailView.Adapter#onClick");
             UserRecord userRecord =
                     (UserRecord) view.getTag();
-            if (mController.isDisabledByAdmin(userRecord)) {
+            if (userRecord.isDisabledByAdmin()) {
                 final Intent intent = RestrictedLockUtils.getShowAdminSupportDetailsIntent(
-                        mContext, mController.getEnforcedAdmin(userRecord));
+                        mContext, userRecord.enforcedAdmin);
                 mController.startActivity(intent);
             } else if (userRecord.isSwitchToEnabled) {
                 MetricsLogger.action(mContext, MetricsEvent.QS_SWITCH_USER);
                 mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_SWITCH);
                 if (!userRecord.isAddUser
                         && !userRecord.isRestricted
-                        && !mController.isDisabledByAdmin(userRecord)) {
+                        && !userRecord.isDisabledByAdmin()) {
                     if (mCurrentUserView != null) {
                         mCurrentUserView.setActivated(false);
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index 3c8775d0..9c0a087 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -197,7 +197,7 @@
             };
 
     protected List<SubscriptionInfo> getSubscriptionInfo() {
-        return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
+        return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo();
     }
 
     @Inject
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 95edb35..66be00d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -25,14 +25,6 @@
 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_BACK_ANIMATION;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_FLOATING_TASKS;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
-import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
@@ -109,15 +101,7 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.wm.shell.back.BackAnimation;
-import com.android.wm.shell.floating.FloatingTasks;
-import com.android.wm.shell.onehanded.OneHanded;
-import com.android.wm.shell.pip.Pip;
-import com.android.wm.shell.pip.PipAnimationController;
-import com.android.wm.shell.recents.RecentTasks;
-import com.android.wm.shell.splitscreen.SplitScreen;
-import com.android.wm.shell.startingsurface.StartingSurface;
-import com.android.wm.shell.transition.ShellTransitions;
+import com.android.wm.shell.sysui.ShellInterface;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -149,10 +133,8 @@
     private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
 
     private final Context mContext;
-    private final Optional<Pip> mPipOptional;
+    private final ShellInterface mShellInterface;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
-    private final Optional<SplitScreen> mSplitScreenOptional;
-    private final Optional<FloatingTasks> mFloatingTasksOptional;
     private SysUiState mSysUiState;
     private final Handler mHandler;
     private final Lazy<NavigationBarController> mNavBarControllerLazy;
@@ -162,13 +144,8 @@
     private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
     private final Intent mQuickStepIntent;
     private final ScreenshotHelper mScreenshotHelper;
-    private final Optional<OneHanded> mOneHandedOptional;
     private final CommandQueue mCommandQueue;
-    private final ShellTransitions mShellTransitions;
-    private final Optional<StartingSurface> mStartingSurface;
     private final KeyguardUnlockAnimationController mSysuiUnlockAnimationController;
-    private final Optional<RecentTasks> mRecentTasks;
-    private final Optional<BackAnimation> mBackAnimation;
     private final UiEventLogger mUiEventLogger;
 
     private Region mActiveNavBarRegion;
@@ -339,14 +316,6 @@
         }
 
         @Override
-        public void notifySwipeToHomeFinished() {
-            verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () ->
-                    mPipOptional.ifPresent(
-                            pip -> pip.setPinnedStackAnimationType(
-                                    PipAnimationController.ANIM_TYPE_ALPHA)));
-        }
-
-        @Override
         public void notifySwipeUpGestureStarted() {
             verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () ->
                     notifySwipeUpGestureStartedInternal());
@@ -461,33 +430,10 @@
             params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
             params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
             params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
-
-            mPipOptional.ifPresent((pip) -> params.putBinder(
-                    KEY_EXTRA_SHELL_PIP,
-                    pip.createExternalInterface().asBinder()));
-            mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
-                    KEY_EXTRA_SHELL_SPLIT_SCREEN,
-                    splitscreen.createExternalInterface().asBinder()));
-            mFloatingTasksOptional.ifPresent(floatingTasks -> params.putBinder(
-                    KEY_EXTRA_SHELL_FLOATING_TASKS,
-                    floatingTasks.createExternalInterface().asBinder()));
-            mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
-                    KEY_EXTRA_SHELL_ONE_HANDED,
-                    onehanded.createExternalInterface().asBinder()));
-            params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
-                    mShellTransitions.createExternalInterface().asBinder());
-            mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
-                    KEY_EXTRA_SHELL_STARTING_WINDOW,
-                    startingwindow.createExternalInterface().asBinder()));
-            params.putBinder(
-                    KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER,
+            params.putBinder(KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER,
                     mSysuiUnlockAnimationController.asBinder());
-            mRecentTasks.ifPresent(recentTasks -> params.putBinder(
-                    KEY_EXTRA_RECENT_TASKS,
-                    recentTasks.createExternalInterface().asBinder()));
-            mBackAnimation.ifPresent((backAnimation) -> params.putBinder(
-                    KEY_EXTRA_SHELL_BACK_ANIMATION,
-                    backAnimation.createExternalInterface().asBinder()));
+            // Add all the interfaces exposed by the shell
+            mShellInterface.createExternalInterfaces(params);
 
             try {
                 Log.d(TAG_OPS, "OverviewProxyService connected, initializing overview proxy");
@@ -561,20 +507,14 @@
 
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
-    public OverviewProxyService(Context context, CommandQueue commandQueue,
+    public OverviewProxyService(Context context,
+            CommandQueue commandQueue,
+            ShellInterface shellInterface,
             Lazy<NavigationBarController> navBarControllerLazy,
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             NavigationModeController navModeController,
             NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
-            Optional<Pip> pipOptional,
-            Optional<SplitScreen> splitScreenOptional,
-            Optional<FloatingTasks> floatingTasksOptional,
-            Optional<OneHanded> oneHandedOptional,
-            Optional<RecentTasks> recentTasks,
-            Optional<BackAnimation> backAnimation,
-            Optional<StartingSurface> startingSurface,
             BroadcastDispatcher broadcastDispatcher,
-            ShellTransitions shellTransitions,
             ScreenLifecycle screenLifecycle,
             UiEventLogger uiEventLogger,
             KeyguardUnlockAnimationController sysuiUnlockAnimationController,
@@ -588,7 +528,7 @@
         }
 
         mContext = context;
-        mPipOptional = pipOptional;
+        mShellInterface = shellInterface;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
         mHandler = new Handler();
         mNavBarControllerLazy = navBarControllerLazy;
@@ -603,10 +543,6 @@
                 .supportsRoundedCornersOnWindows(mContext.getResources());
         mSysUiState = sysUiState;
         mSysUiState.addCallback(this::notifySystemUiStateFlags);
-        mOneHandedOptional = oneHandedOptional;
-        mShellTransitions = shellTransitions;
-        mRecentTasks = recentTasks;
-        mBackAnimation = backAnimation;
         mUiEventLogger = uiEventLogger;
 
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
@@ -636,9 +572,6 @@
         });
         mCommandQueue = commandQueue;
 
-        mSplitScreenOptional = splitScreenOptional;
-        mFloatingTasksOptional = floatingTasksOptional;
-
         // Listen for user setup
         startTracking();
 
@@ -647,7 +580,6 @@
         // Connect to the service
         updateEnabledState();
         startConnectionToCurrentUser();
-        mStartingSurface = startingSurface;
         mSysuiUnlockAnimationController = sysuiUnlockAnimationController;
 
         // Listen for assistant changes
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
index 55602a9..e3658de 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageExporter.java
@@ -19,6 +19,7 @@
 import static android.os.FileUtils.closeQuietly;
 
 import android.annotation.IntRange;
+import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.graphics.Bitmap;
@@ -29,6 +30,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.provider.MediaStore;
 import android.util.Log;
 
@@ -142,8 +144,9 @@
      *
      * @return a listenable future result
      */
-    ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap) {
-        return export(executor, requestId, bitmap, ZonedDateTime.now());
+    ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
+            UserHandle owner) {
+        return export(executor, requestId, bitmap, ZonedDateTime.now(), owner);
     }
 
     /**
@@ -155,10 +158,10 @@
      * @return a listenable future result
      */
     ListenableFuture<Result> export(Executor executor, UUID requestId, Bitmap bitmap,
-            ZonedDateTime captureTime) {
+            ZonedDateTime captureTime, UserHandle owner) {
 
         final Task task = new Task(mResolver, requestId, bitmap, captureTime, mCompressFormat,
-                mQuality, /* publish */ true);
+                mQuality, /* publish */ true, owner);
 
         return CallbackToFutureAdapter.getFuture(
                 (completer) -> {
@@ -174,28 +177,6 @@
         );
     }
 
-    /**
-     * Delete the entry.
-     *
-     * @param executor the thread for execution
-     * @param uri the uri of the image to publish
-     *
-     * @return a listenable future result
-     */
-    ListenableFuture<Result> delete(Executor executor, Uri uri) {
-        return CallbackToFutureAdapter.getFuture((completer) -> {
-            executor.execute(() -> {
-                mResolver.delete(uri, null);
-
-                Result result = new Result();
-                result.uri = uri;
-                result.deleted = true;
-                completer.set(result);
-            });
-            return "ContentResolver#delete";
-        });
-    }
-
     static class Result {
         Uri uri;
         UUID requestId;
@@ -203,7 +184,6 @@
         long timestamp;
         CompressFormat format;
         boolean published;
-        boolean deleted;
 
         @Override
         public String toString() {
@@ -214,7 +194,6 @@
             sb.append(", timestamp=").append(timestamp);
             sb.append(", format=").append(format);
             sb.append(", published=").append(published);
-            sb.append(", deleted=").append(deleted);
             sb.append('}');
             return sb.toString();
         }
@@ -227,17 +206,19 @@
         private final ZonedDateTime mCaptureTime;
         private final CompressFormat mFormat;
         private final int mQuality;
+        private final UserHandle mOwner;
         private final String mFileName;
         private final boolean mPublish;
 
         Task(ContentResolver resolver, UUID requestId, Bitmap bitmap, ZonedDateTime captureTime,
-                CompressFormat format, int quality, boolean publish) {
+                CompressFormat format, int quality, boolean publish, UserHandle owner) {
             mResolver = resolver;
             mRequestId = requestId;
             mBitmap = bitmap;
             mCaptureTime = captureTime;
             mFormat = format;
             mQuality = quality;
+            mOwner = owner;
             mFileName = createFilename(mCaptureTime, mFormat);
             mPublish = publish;
         }
@@ -253,7 +234,7 @@
                     start = Instant.now();
                 }
 
-                uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName);
+                uri = createEntry(mResolver, mFormat, mCaptureTime, mFileName, mOwner);
                 throwIfInterrupted();
 
                 writeImage(mResolver, mBitmap, mFormat, mQuality, uri);
@@ -297,15 +278,20 @@
     }
 
     private static Uri createEntry(ContentResolver resolver, CompressFormat format,
-            ZonedDateTime time, String fileName) throws ImageExportException {
+            ZonedDateTime time, String fileName, UserHandle owner) throws ImageExportException {
         Trace.beginSection("ImageExporter_createEntry");
         try {
             final ContentValues values = createMetadata(time, format, fileName);
 
-            Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+            Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
+            if (UserHandle.myUserId() != owner.getIdentifier()) {
+                baseUri = ContentProvider.maybeAddUserId(baseUri, owner.getIdentifier());
+            }
+            Uri uri = resolver.insert(baseUri, values);
             if (uri == null) {
                 throw new ImageExportException(RESOLVER_INSERT_RETURNED_NULL);
             }
+            Log.d(TAG, "Inserted new URI: " + uri);
             return uri;
         } finally {
             Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
index ba6e98e..8bf956b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/LongScreenshotActivity.java
@@ -30,6 +30,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.Log;
@@ -387,7 +388,9 @@
 
         mOutputBitmap = renderBitmap(drawable, bounds);
         ListenableFuture<ImageExporter.Result> exportFuture = mImageExporter.export(
-                mBackgroundExecutor, UUID.randomUUID(), mOutputBitmap, ZonedDateTime.now());
+                mBackgroundExecutor, UUID.randomUUID(), mOutputBitmap, ZonedDateTime.now(),
+                // TODO: Owner must match the owner of the captured window.
+                Process.myUserHandle());
         exportFuture.addListener(() -> onExportCompleted(action, exportFuture), mUiExecutor);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index f248d69..077ad35 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -48,6 +48,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.systemui.R;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -71,6 +73,7 @@
     private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
 
     private final Context mContext;
+    private FeatureFlags mFlags;
     private final ScreenshotSmartActions mScreenshotSmartActions;
     private final ScreenshotController.SaveImageInBackgroundData mParams;
     private final ScreenshotController.SavedImageData mImageData;
@@ -84,7 +87,10 @@
     private final ImageExporter mImageExporter;
     private long mImageTime;
 
-    SaveImageInBackgroundTask(Context context, ImageExporter exporter,
+    SaveImageInBackgroundTask(
+            Context context,
+            FeatureFlags flags,
+            ImageExporter exporter,
             ScreenshotSmartActions screenshotSmartActions,
             ScreenshotController.SaveImageInBackgroundData data,
             Supplier<ActionTransition> sharedElementTransition,
@@ -92,6 +98,7 @@
                     screenshotNotificationSmartActionsProvider
     ) {
         mContext = context;
+        mFlags = flags;
         mScreenshotSmartActions = screenshotSmartActions;
         mImageData = new ScreenshotController.SavedImageData();
         mQuickShareData = new ScreenshotController.QuickShareData();
@@ -117,7 +124,8 @@
         }
         // TODO: move to constructor / from ScreenshotRequest
         final UUID requestId = UUID.randomUUID();
-        final UserHandle user = getUserHandleOfForegroundApplication(mContext);
+        final UserHandle user = mFlags.isEnabled(Flags.SCREENSHOT_WORK_PROFILE_POLICY)
+                ? mParams.owner : getUserHandleOfForegroundApplication(mContext);
 
         Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
 
@@ -133,8 +141,9 @@
 
             // Call synchronously here since already on a background thread.
             ListenableFuture<ImageExporter.Result> future =
-                    mImageExporter.export(Runnable::run, requestId, image);
+                    mImageExporter.export(Runnable::run, requestId, image, mParams.owner);
             ImageExporter.Result result = future.get();
+            Log.d(TAG, "Saved screenshot: " + result);
             final Uri uri = result.uri;
             mImageTime = result.timestamp;
 
@@ -157,6 +166,7 @@
             }
 
             mImageData.uri = uri;
+            mImageData.owner = user;
             mImageData.smartActions = smartActions;
             mImageData.shareTransition = createShareAction(mContext, mContext.getResources(), uri);
             mImageData.editTransition = createEditAction(mContext, mContext.getResources(), uri);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 3fee232..704e115 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -34,6 +34,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.MainThread;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
@@ -57,7 +58,9 @@
 import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -90,6 +93,7 @@
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.clipboardoverlay.ClipboardOverlayController;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.screenshot.ScreenshotController.SavedImageData.ActionTransition;
 import com.android.systemui.screenshot.TakeScreenshotService.RequestCallback;
 import com.android.systemui.util.Assert;
@@ -151,6 +155,7 @@
         public Consumer<Uri> finisher;
         public ScreenshotController.ActionsReadyListener mActionsReadyListener;
         public ScreenshotController.QuickShareActionReadyListener mQuickShareActionsReadyListener;
+        public UserHandle owner;
 
         void clearImage() {
             image = null;
@@ -167,6 +172,8 @@
         public Notification.Action deleteAction;
         public List<Notification.Action> smartActions;
         public Notification.Action quickShareAction;
+        public UserHandle owner;
+
 
         /**
          * POD for shared element transition.
@@ -242,6 +249,7 @@
     private static final int SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS = 6000;
 
     private final WindowContext mContext;
+    private final FeatureFlags mFlags;
     private final ScreenshotNotificationsController mNotificationsController;
     private final ScreenshotSmartActions mScreenshotSmartActions;
     private final UiEventLogger mUiEventLogger;
@@ -288,6 +296,7 @@
     @Inject
     ScreenshotController(
             Context context,
+            FeatureFlags flags,
             ScreenshotSmartActions screenshotSmartActions,
             ScreenshotNotificationsController screenshotNotificationsController,
             ScrollCaptureClient scrollCaptureClient,
@@ -331,6 +340,7 @@
         final Context displayContext = context.createDisplayContext(getDefaultDisplay());
         mContext = (WindowContext) displayContext.createWindowContext(TYPE_SCREENSHOT, null);
         mWindowManager = mContext.getSystemService(WindowManager.class);
+        mFlags = flags;
 
         mAccessibilityManager = AccessibilityManager.getInstance(mContext);
 
@@ -377,7 +387,6 @@
     void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
             Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
             Consumer<Uri> finisher, RequestCallback requestCallback) {
-        // TODO: use task Id, userId, topComponent for smart handler
         Assert.isMainThread();
         if (screenshot == null) {
             Log.e(TAG, "Got null bitmap from screenshot message");
@@ -395,25 +404,7 @@
         }
         mCurrentRequestCallback = requestCallback;
         saveScreenshot(screenshot, finisher, screenshotScreenBounds, visibleInsets, topComponent,
-                showFlash);
-    }
-
-    /**
-     * Displays a screenshot selector
-     */
-    @MainThread
-    void takeScreenshotPartial(ComponentName topComponent,
-            final Consumer<Uri> finisher, RequestCallback requestCallback) {
-        Assert.isMainThread();
-        mScreenshotView.reset();
-        mCurrentRequestCallback = requestCallback;
-
-        attachWindow();
-        mWindow.setContentView(mScreenshotView);
-        mScreenshotView.requestApplyInsets();
-
-        mScreenshotView.takePartialScreenshot(
-                rect -> takeScreenshotInternal(topComponent, finisher, rect));
+                showFlash, UserHandle.of(userId));
     }
 
     /**
@@ -543,14 +534,15 @@
             return;
         }
 
-        saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true);
+        saveScreenshot(screenshot, finisher, screenRect, Insets.NONE, topComponent, true,
+                Process.myUserHandle());
 
         mBroadcastSender.sendBroadcast(new Intent(ClipboardOverlayController.SCREENSHOT_ACTION),
                 ClipboardOverlayController.SELF_PERMISSION);
     }
 
     private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
-            Insets screenInsets, ComponentName topComponent, boolean showFlash) {
+            Insets screenInsets, ComponentName topComponent, boolean showFlash, UserHandle owner) {
         withWindowAttached(() ->
                 mScreenshotView.announceForAccessibility(
                         mContext.getResources().getString(R.string.screenshot_saving_title)));
@@ -575,11 +567,11 @@
 
         mScreenBitmap = screenshot;
 
-        if (!isUserSetupComplete()) {
+        if (!isUserSetupComplete(owner)) {
             Log.w(TAG, "User setup not complete, displaying toast only");
             // User setup isn't complete, so we don't want to show any UI beyond a toast, as editing
             // and sharing shouldn't be exposed to the user.
-            saveScreenshotAndToast(finisher);
+            saveScreenshotAndToast(owner, finisher);
             return;
         }
 
@@ -587,7 +579,7 @@
         mScreenBitmap.setHasAlpha(false);
         mScreenBitmap.prepareToDraw();
 
-        saveScreenshotInWorkerThread(finisher, this::showUiOnActionsReady,
+        saveScreenshotInWorkerThread(owner, finisher, this::showUiOnActionsReady,
                 this::showUiOnQuickShareActionReady);
 
         // The window is focusable by default
@@ -853,11 +845,12 @@
      * Save the bitmap but don't show the normal screenshot UI.. just a toast (or notification on
      * failure).
      */
-    private void saveScreenshotAndToast(Consumer<Uri> finisher) {
+    private void saveScreenshotAndToast(UserHandle owner, Consumer<Uri> finisher) {
         // Play the shutter sound to notify that we've taken a screenshot
         playCameraSound();
 
         saveScreenshotInWorkerThread(
+                owner,
                 /* onComplete */ finisher,
                 /* actionsReadyListener */ imageData -> {
                     if (DEBUG_CALLBACK) {
@@ -925,9 +918,11 @@
     /**
      * Creates a new worker thread and saves the screenshot to the media store.
      */
-    private void saveScreenshotInWorkerThread(Consumer<Uri> finisher,
-            @Nullable ScreenshotController.ActionsReadyListener actionsReadyListener,
-            @Nullable ScreenshotController.QuickShareActionReadyListener
+    private void saveScreenshotInWorkerThread(
+            UserHandle owner,
+            @NonNull Consumer<Uri> finisher,
+            @Nullable ActionsReadyListener actionsReadyListener,
+            @Nullable QuickShareActionReadyListener
                     quickShareActionsReadyListener) {
         ScreenshotController.SaveImageInBackgroundData
                 data = new ScreenshotController.SaveImageInBackgroundData();
@@ -935,13 +930,14 @@
         data.finisher = finisher;
         data.mActionsReadyListener = actionsReadyListener;
         data.mQuickShareActionsReadyListener = quickShareActionsReadyListener;
+        data.owner = owner;
 
         if (mSaveInBgTask != null) {
             // just log success/failure for the pre-existing screenshot
             mSaveInBgTask.setActionsReadyListener(this::logSuccessOnActionsReady);
         }
 
-        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mImageExporter,
+        mSaveInBgTask = new SaveImageInBackgroundTask(mContext, mFlags, mImageExporter,
                 mScreenshotSmartActions, data, getActionTransitionSupplier(),
                 mScreenshotNotificationSmartActionsProvider);
         mSaveInBgTask.execute();
@@ -960,6 +956,15 @@
         mScreenshotHandler.resetTimeout();
 
         if (imageData.uri != null) {
+            if (!imageData.owner.equals(Process.myUserHandle())) {
+                // TODO: Handle non-primary user ownership (e.g. Work Profile)
+                // This image is owned by another user. Special treatment will be
+                // required in the UI (badging) as well as sending intents which can
+                // correctly forward those URIs on to be read (actions).
+
+                Log.d(TAG, "*** Screenshot saved to a non-primary user ("
+                        + imageData.owner + ") as " + imageData.uri);
+            }
             mScreenshotHandler.post(() -> {
                 if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
                     mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
@@ -1033,9 +1038,9 @@
         }
     }
 
-    private boolean isUserSetupComplete() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
-                SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
+    private boolean isUserSetupComplete(UserHandle owner) {
+        return Settings.Secure.getInt(mContext.createContextAsUser(owner, 0)
+                        .getContentResolver(), SETTINGS_SECURE_USER_SETUP_COMPLETE, 0) == 1;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
index c2a5060..3a35286 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotPolicyImpl.kt
@@ -68,7 +68,9 @@
     }
 
     override suspend fun isManagedProfile(@UserIdInt userId: Int): Boolean {
-        return withContext(bgDispatcher) { userMgr.isManagedProfile(userId) }
+        val managed = withContext(bgDispatcher) { userMgr.isManagedProfile(userId) }
+        Log.d(TAG, "isManagedProfile: $managed")
+        return managed
     }
 
     private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java
deleted file mode 100644
index c793b5b..0000000
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSelectorView.java
+++ /dev/null
@@ -1,119 +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.screenshot;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-
-import java.util.function.Consumer;
-
-/**
- * Draws a selection rectangle while taking screenshot
- */
-public class ScreenshotSelectorView extends View {
-    private Point mStartPoint;
-    private Rect mSelectionRect;
-    private final Paint mPaintSelection, mPaintBackground;
-
-    private Consumer<Rect> mOnScreenshotSelected;
-
-    public ScreenshotSelectorView(Context context) {
-        this(context, null);
-    }
-
-    public ScreenshotSelectorView(Context context, @Nullable AttributeSet attrs) {
-        super(context, attrs);
-        mPaintBackground = new Paint(Color.BLACK);
-        mPaintBackground.setAlpha(160);
-        mPaintSelection = new Paint(Color.TRANSPARENT);
-        mPaintSelection.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-
-        setOnTouchListener((v, event) -> {
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    startSelection((int) event.getX(), (int) event.getY());
-                    return true;
-                case MotionEvent.ACTION_MOVE:
-                    updateSelection((int) event.getX(), (int) event.getY());
-                    return true;
-                case MotionEvent.ACTION_UP:
-                    setVisibility(View.GONE);
-                    final Rect rect = getSelectionRect();
-                    if (mOnScreenshotSelected != null
-                            && rect != null
-                            && rect.width() != 0 && rect.height() != 0) {
-                        mOnScreenshotSelected.accept(rect);
-                    }
-                    stopSelection();
-                    return true;
-            }
-            return false;
-        });
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        canvas.drawRect(mLeft, mTop, mRight, mBottom, mPaintBackground);
-        if (mSelectionRect != null) {
-            canvas.drawRect(mSelectionRect, mPaintSelection);
-        }
-    }
-
-    void setOnScreenshotSelected(Consumer<Rect> onScreenshotSelected) {
-        mOnScreenshotSelected = onScreenshotSelected;
-    }
-
-    void stop() {
-        if (getSelectionRect() != null) {
-            stopSelection();
-        }
-    }
-
-    private void startSelection(int x, int y) {
-        mStartPoint = new Point(x, y);
-        mSelectionRect = new Rect(x, y, x, y);
-    }
-
-    private void updateSelection(int x, int y) {
-        if (mSelectionRect != null) {
-            mSelectionRect.left = Math.min(mStartPoint.x, x);
-            mSelectionRect.right = Math.max(mStartPoint.x, x);
-            mSelectionRect.top = Math.min(mStartPoint.y, y);
-            mSelectionRect.bottom = Math.max(mStartPoint.y, y);
-            invalidate();
-        }
-    }
-
-    private Rect getSelectionRect() {
-        return mSelectionRect;
-    }
-
-    private void stopSelection() {
-        mStartPoint = null;
-        mSelectionRect = null;
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 360fc87..be41a6b 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -93,7 +93,6 @@
 import com.android.systemui.shared.system.QuickStepContract;
 
 import java.util.ArrayList;
-import java.util.function.Consumer;
 
 /**
  * Handles the visual elements and animations for the screenshot flow.
@@ -141,7 +140,6 @@
     private boolean mOrientationPortrait;
     private boolean mDirectionLTR;
 
-    private ScreenshotSelectorView mScreenshotSelectorView;
     private ImageView mScrollingScrim;
     private DraggableConstraintLayout mScreenshotStatic;
     private ImageView mScreenshotPreview;
@@ -361,7 +359,6 @@
         mDismissButton = requireNonNull(findViewById(R.id.screenshot_dismiss_button));
         mScrollablePreview = requireNonNull(findViewById(R.id.screenshot_scrollable_preview));
         mScreenshotFlash = requireNonNull(findViewById(R.id.screenshot_flash));
-        mScreenshotSelectorView = requireNonNull(findViewById(R.id.screenshot_selector));
         mShareChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_share_chip));
         mEditChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_edit_chip));
         mScrollChip = requireNonNull(mActionsContainer.findViewById(R.id.screenshot_scroll_chip));
@@ -377,8 +374,6 @@
         mActionsContainerBackground.setTouchDelegate(actionsDelegate);
 
         setFocusable(true);
-        mScreenshotSelectorView.setFocusable(true);
-        mScreenshotSelectorView.setFocusableInTouchMode(true);
         mActionsContainer.setScrollX(0);
 
         mNavMode = getResources().getInteger(
@@ -432,12 +427,6 @@
         mCallbacks = callbacks;
     }
 
-    void takePartialScreenshot(Consumer<Rect> onPartialScreenshotSelected) {
-        mScreenshotSelectorView.setOnScreenshotSelected(onPartialScreenshotSelected);
-        mScreenshotSelectorView.setVisibility(View.VISIBLE);
-        mScreenshotSelectorView.requestFocus();
-    }
-
     void setScreenshot(Bitmap bitmap, Insets screenInsets) {
         mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
     }
@@ -1031,7 +1020,6 @@
         mQuickShareChip = null;
         setAlpha(1);
         mScreenshotStatic.setAlpha(1);
-        mScreenshotSelectorView.stop();
     }
 
     private void startSharedTransition(ActionTransition transition) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 83b60fb..30a0b8f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -78,6 +78,7 @@
     static class LongScreenshot {
         private final ImageTileSet mImageTileSet;
         private final Session mSession;
+        // TODO: Add UserHandle so LongScreenshots can adhere to work profile screenshot policy
 
         LongScreenshot(Session session, ImageTileSet imageTileSet) {
             mSession = session;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 695a80b..a4a59ce 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -249,12 +249,6 @@
                 }
                 mScreenshot.takeScreenshotFullscreen(topComponent, uriConsumer, callback);
                 break;
-            case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION:
-                if (DEBUG_SERVICE) {
-                    Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_SELECTED_REGION");
-                }
-                mScreenshot.takeScreenshotPartial(topComponent, uriConsumer, callback);
-                break;
             case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
                 if (DEBUG_SERVICE) {
                     Log.d(TAG, "handleMessage: TAKE_SCREENSHOT_PROVIDED_IMAGE");
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
index a22fda7..6e9f859 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessDialog.java
@@ -25,6 +25,7 @@
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
@@ -76,6 +77,12 @@
         FrameLayout frame = findViewById(R.id.brightness_mirror_container);
         // The brightness mirror container is INVISIBLE by default.
         frame.setVisibility(View.VISIBLE);
+        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) frame.getLayoutParams();
+        int horizontalMargin =
+                getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
+        lp.leftMargin = horizontalMargin;
+        lp.rightMargin = horizontalMargin;
+        frame.setLayoutParams(lp);
 
         BrightnessSliderController controller = mToggleSliderFactory.create(this, frame);
         controller.init();
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index fe40d4c..d3ed474 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -48,6 +48,7 @@
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QS_HEADER_CONSTRAINT
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_BATTERY_CONTROLLER
@@ -261,7 +262,7 @@
         batteryMeterViewController.ignoreTunerUpdates()
         batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
 
-        iconManager = tintedIconManagerFactory.create(iconContainer)
+        iconManager = tintedIconManagerFactory.create(iconContainer, StatusBarLocation.QS)
         iconManager.setTint(
             Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary)
         )
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
index e0cd482..ba779c6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelUnfoldAnimationController.kt
@@ -20,8 +20,8 @@
 import android.view.ViewGroup
 import com.android.systemui.R
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator
-import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.LEFT
-import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.RIGHT
+import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.END
+import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.Direction.START
 import com.android.systemui.shared.animation.UnfoldConstantTranslateAnimator.ViewIdToTranslate
 import com.android.systemui.unfold.SysUIUnfoldScope
 import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider
@@ -36,11 +36,11 @@
         UnfoldConstantTranslateAnimator(
             viewsIdToTranslate =
                 setOf(
-                    ViewIdToTranslate(R.id.quick_settings_panel, LEFT),
-                    ViewIdToTranslate(R.id.notification_stack_scroller, RIGHT),
-                    ViewIdToTranslate(R.id.rightLayout, RIGHT),
-                    ViewIdToTranslate(R.id.clock, LEFT),
-                    ViewIdToTranslate(R.id.date, LEFT)),
+                    ViewIdToTranslate(R.id.quick_settings_panel, START),
+                    ViewIdToTranslate(R.id.notification_stack_scroller, END),
+                    ViewIdToTranslate(R.id.rightLayout, END),
+                    ViewIdToTranslate(R.id.clock, START),
+                    ViewIdToTranslate(R.id.date, START)),
             progressProvider = progressProvider)
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index d7e86b6..1110386 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -425,11 +425,10 @@
             new KeyguardClockPositionAlgorithm.Result();
     private boolean mIsExpanding;
 
-    private boolean mBlockTouches;
-
     /**
      * Determines if QS should be already expanded when expanding shade.
      * Used for split shade, two finger gesture as well as accessibility shortcut to QS.
+     * It needs to be set when movement starts as it resets at the end of expansion/collapse.
      */
     @VisibleForTesting
     boolean mQsExpandImmediate;
@@ -1692,7 +1691,6 @@
 
     public void resetViews(boolean animate) {
         mIsLaunchTransitionFinished = false;
-        mBlockTouches = false;
         mCentralSurfaces.getGutsManager().closeAndSaveGuts(true /* leavebehind */, true /* force */,
                 true /* controls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
         if (animate && !isFullyCollapsed()) {
@@ -1737,8 +1735,10 @@
     }
 
     private void setQsExpandImmediate(boolean expandImmediate) {
-        mQsExpandImmediate = expandImmediate;
-        mPanelEventsEmitter.notifyExpandImmediateChange(expandImmediate);
+        if (expandImmediate != mQsExpandImmediate) {
+            mQsExpandImmediate = expandImmediate;
+            mPanelEventsEmitter.notifyExpandImmediateChange(expandImmediate);
+        }
     }
 
     private void setShowShelfOnly(boolean shelfOnly) {
@@ -2479,17 +2479,23 @@
         mDepthController.setQsPanelExpansion(qsExpansionFraction);
         mStatusBarKeyguardViewManager.setQsExpansion(qsExpansionFraction);
 
-        // updateQsExpansion will get called whenever mTransitionToFullShadeProgress or
-        // mLockscreenShadeTransitionController.getDragProgress change.
-        // When in lockscreen, getDragProgress indicates the true expanded fraction of QS
-        float shadeExpandedFraction = mTransitioningToFullShadeProgress > 0
-                ? mLockscreenShadeTransitionController.getQSDragProgress()
+        float shadeExpandedFraction = isOnKeyguard()
+                ? getLockscreenShadeDragProgress()
                 : getExpandedFraction();
         mLargeScreenShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
         mLargeScreenShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
         mLargeScreenShadeHeaderController.setQsVisible(mQsVisible);
     }
 
+    private float getLockscreenShadeDragProgress() {
+        // mTransitioningToFullShadeProgress > 0 means we're doing regular lockscreen to shade
+        // transition. If that's not the case we should follow QS expansion fraction for when
+        // user is pulling from the same top to go directly to expanded QS
+        return mTransitioningToFullShadeProgress > 0
+                ? mLockscreenShadeTransitionController.getQSDragProgress()
+                : computeQsExpansionFraction();
+    }
+
     private void onStackYChanged(boolean shouldAnimate) {
         if (mQs != null) {
             if (shouldAnimate) {
@@ -3124,26 +3130,24 @@
         }
         if (mQsExpandImmediate || (mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
                 && !mQsExpansionFromOverscroll)) {
-            float t;
-            if (mKeyguardShowing) {
-
+            float qsExpansionFraction;
+            if (mSplitShadeEnabled) {
+                qsExpansionFraction = 1;
+            } else if (mKeyguardShowing) {
                 // On Keyguard, interpolate the QS expansion linearly to the panel expansion
-                t = expandedHeight / (getMaxPanelHeight());
+                qsExpansionFraction = expandedHeight / (getMaxPanelHeight());
             } else {
                 // In Shade, interpolate linearly such that QS is closed whenever panel height is
                 // minimum QS expansion + minStackHeight
-                float
-                        panelHeightQsCollapsed =
+                float panelHeightQsCollapsed =
                         mNotificationStackScrollLayoutController.getIntrinsicPadding()
                                 + mNotificationStackScrollLayoutController.getLayoutMinHeight();
                 float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
-                t =
-                        (expandedHeight - panelHeightQsCollapsed) / (panelHeightQsExpanded
-                                - panelHeightQsCollapsed);
+                qsExpansionFraction = (expandedHeight - panelHeightQsCollapsed)
+                        / (panelHeightQsExpanded - panelHeightQsCollapsed);
             }
-            float
-                    targetHeight =
-                    mQsMinExpansionHeight + t * (mQsMaxExpansionHeight - mQsMinExpansionHeight);
+            float targetHeight = mQsMinExpansionHeight
+                    + qsExpansionFraction * (mQsMaxExpansionHeight - mQsMinExpansionHeight);
             setQsExpansion(targetHeight);
         }
         updateExpandedHeight(expandedHeight);
@@ -3329,7 +3333,11 @@
         } else {
             setListening(true);
         }
-        setQsExpandImmediate(false);
+        if (mBarState != SHADE) {
+            // updating qsExpandImmediate is done in onPanelStateChanged for unlocked shade but
+            // on keyguard panel state is always OPEN so we need to have that extra update
+            setQsExpandImmediate(false);
+        }
         setShowShelfOnly(false);
         mTwoFingerQsExpandPossible = false;
         updateTrackingHeadsUp(null);
@@ -4187,7 +4195,7 @@
                             "NPVC onInterceptTouchEvent (" + event.getId() + "): (" + event.getX()
                                     + "," + event.getY() + ")");
                 }
-                if (mBlockTouches || mQs.disallowPanelTouches()) {
+                if (mQs.disallowPanelTouches()) {
                     return false;
                 }
                 initDownStates(event);
@@ -4230,8 +4238,7 @@
                 }
 
 
-                if (mBlockTouches || (mQsFullyExpanded && mQs != null
-                        && mQs.disallowPanelTouches())) {
+                if (mQsFullyExpanded && mQs != null && mQs.disallowPanelTouches()) {
                     return false;
                 }
 
@@ -4678,12 +4685,19 @@
                     }
                 }
             } else {
+                // this else branch means we are doing one of:
+                //  - from KEYGUARD and SHADE (but not expanded shade)
+                //  - from SHADE to KEYGUARD
+                //  - from SHADE_LOCKED to SHADE
+                //  - getting notified again about the current SHADE or KEYGUARD state
                 final boolean animatingUnlockedShadeToKeyguard = oldState == SHADE
                         && statusBarState == KEYGUARD
                         && mScreenOffAnimationController.isKeyguardShowDelayed();
                 if (!animatingUnlockedShadeToKeyguard) {
                     // Only make the status bar visible if we're not animating the screen off, since
                     // we only want to be showing the clock/notifications during the animation.
+                    mShadeLog.v("Updating keyguard status bar state to "
+                            + (keyguardShowing ? "visible" : "invisible"));
                     mKeyguardStatusBarViewController.updateViewState(
                             /* alpha= */ 1f,
                             keyguardShowing ? View.VISIBLE : View.INVISIBLE);
@@ -4749,9 +4763,7 @@
 
                 @Override
                 public float getLockscreenShadeDragProgress() {
-                    return mTransitioningToFullShadeProgress > 0
-                            ? mLockscreenShadeTransitionController.getQSDragProgress()
-                            : computeQsExpansionFraction();
+                    return NotificationPanelViewController.this.getLockscreenShadeDragProgress();
                 }
             };
 
@@ -4988,6 +5000,7 @@
         updateQSExpansionEnabledAmbient();
 
         if (state == STATE_OPEN && mCurrentPanelState != state) {
+            setQsExpandImmediate(false);
             mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
         if (state == STATE_OPENING) {
@@ -5000,6 +5013,7 @@
             mCentralSurfaces.makeExpandedVisible(false);
         }
         if (state == STATE_CLOSED) {
+            setQsExpandImmediate(false);
             // Close the status bar in the next frame so we can show the end of the
             // animation.
             mView.post(mMaybeHideExpandedRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarFrameLayout.kt
similarity index 80%
rename from packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarFrameLayout.kt
index 4d53064..ce730ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarWifiView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBarFrameLayout.kt
@@ -20,14 +20,16 @@
 import android.widget.FrameLayout
 
 /**
- * A temporary base class that's shared between our old status bar wifi view implementation
- * ([StatusBarWifiView]) and our new status bar wifi view implementation
- * ([ModernStatusBarWifiView]).
+ * A temporary base class that's shared between our old status bar connectivity view implementations
+ * ([StatusBarWifiView], [StatusBarMobileView]) and our new status bar implementations (
+ * [ModernStatusBarWifiView], [ModernStatusBarMobileView]).
  *
  * Once our refactor is over, we should be able to delete this go-between class and the old view
  * class.
  */
-abstract class BaseStatusBarWifiView @JvmOverloads constructor(
+abstract class BaseStatusBarFrameLayout
+@JvmOverloads
+constructor(
     context: Context,
     attrs: AttributeSet? = null,
     defStyleAttrs: Int = 0,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 8699441..c290ce2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -42,7 +42,6 @@
 
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
@@ -97,6 +96,7 @@
     private final List<UserChangedListener> mListeners = new ArrayList<>();
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final NotificationClickNotifier mClickNotifier;
+    private final Lazy<OverviewProxyService> mOverviewProxyServiceLazy;
 
     private boolean mShowLockscreenNotifications;
     private boolean mAllowLockscreenRemoteInput;
@@ -157,7 +157,7 @@
                     break;
                 case Intent.ACTION_USER_UNLOCKED:
                     // Start the overview connection to the launcher service
-                    Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
+                    mOverviewProxyServiceLazy.get().startConnectionToCurrentUser();
                     break;
                 case NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION:
                     final IntentSender intentSender = intent.getParcelableExtra(
@@ -199,6 +199,7 @@
             Lazy<NotificationVisibilityProvider> visibilityProviderLazy,
             Lazy<CommonNotifCollection> commonNotifCollectionLazy,
             NotificationClickNotifier clickNotifier,
+            Lazy<OverviewProxyService> overviewProxyServiceLazy,
             KeyguardManager keyguardManager,
             StatusBarStateController statusBarStateController,
             @Main Handler mainHandler,
@@ -214,6 +215,7 @@
         mVisibilityProviderLazy = visibilityProviderLazy;
         mCommonNotifCollectionLazy = commonNotifCollectionLazy;
         mClickNotifier = clickNotifier;
+        mOverviewProxyServiceLazy = overviewProxyServiceLazy;
         statusBarStateController.addCallback(this);
         mLockPatternUtils = new LockPatternUtils(context);
         mKeyguardManager = keyguardManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index c900c5a..4be5a1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -43,7 +43,6 @@
 import android.view.View;
 import android.widget.ImageView;
 
-import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -89,11 +88,9 @@
     private static final String TAG = "NotificationMediaManager";
     public static final boolean DEBUG_MEDIA = false;
 
-    private final StatusBarStateController mStatusBarStateController
-            = Dependency.get(StatusBarStateController.class);
-    private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
-    private final KeyguardStateController mKeyguardStateController = Dependency.get(
-            KeyguardStateController.class);
+    private final StatusBarStateController mStatusBarStateController;
+    private final SysuiColorExtractor mColorExtractor;
+    private final KeyguardStateController mKeyguardStateController;
     private final KeyguardBypassController mKeyguardBypassController;
     private static final HashSet<Integer> PAUSED_MEDIA_STATES = new HashSet<>();
     private static final HashSet<Integer> CONNECTING_MEDIA_STATES = new HashSet<>();
@@ -179,6 +176,9 @@
             NotifCollection notifCollection,
             @Main DelayableExecutor mainExecutor,
             MediaDataManager mediaDataManager,
+            StatusBarStateController statusBarStateController,
+            SysuiColorExtractor colorExtractor,
+            KeyguardStateController keyguardStateController,
             DumpManager dumpManager) {
         mContext = context;
         mMediaArtworkProcessor = mediaArtworkProcessor;
@@ -192,6 +192,9 @@
         mMediaDataManager = mediaDataManager;
         mNotifPipeline = notifPipeline;
         mNotifCollection = notifCollection;
+        mStatusBarStateController = statusBarStateController;
+        mColorExtractor = colorExtractor;
+        mKeyguardStateController = keyguardStateController;
 
         setupNotifPipeline();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 41c0367..f961984 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -168,6 +168,17 @@
         return new ShelfState();
     }
 
+    @Override
+    public String toString() {
+        return "NotificationShelf("
+                + "hideBackground=" + mHideBackground + " notGoneIndex=" + mNotGoneIndex
+                + " hasItemsInStableShelf=" + mHasItemsInStableShelf
+                + " statusBarState=" + mStatusBarState + " interactive=" + mInteractive
+                + " animationsEnabled=" + mAnimationsEnabled
+                + " showNotificationShelf=" + mShowNotificationShelf
+                + " indexOfFirstViewInShelf=" + mIndexOfFirstViewInShelf + ')';
+    }
+
     /** Update the state of the shelf. */
     public void updateState(StackScrollAlgorithm.StackScrollAlgorithmState algorithmState,
             AmbientState ambientState) {
@@ -178,22 +189,22 @@
             viewState.copyFrom(lastViewState);
 
             viewState.height = getIntrinsicHeight();
-            viewState.zTranslation = ambientState.getBaseZHeight();
+            viewState.setZTranslation(ambientState.getBaseZHeight());
             viewState.clipTopAmount = 0;
 
             if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
                 float expansion = ambientState.getExpansionFraction();
                 if (ambientState.isBouncerInTransit()) {
-                    viewState.alpha = aboutToShowBouncerProgress(expansion);
+                    viewState.setAlpha(aboutToShowBouncerProgress(expansion));
                 } else {
-                    viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+                    viewState.setAlpha(ShadeInterpolation.getContentAlpha(expansion));
                 }
             } else {
-                viewState.alpha = 1f - ambientState.getHideAmount();
+                viewState.setAlpha(1f - ambientState.getHideAmount());
             }
             viewState.belowSpeedBump = mHostLayoutController.getSpeedBumpIndex() == 0;
             viewState.hideSensitive = false;
-            viewState.xTranslation = getTranslationX();
+            viewState.setXTranslation(getTranslationX());
             viewState.hasItemsInStableShelf = lastViewState.inShelf;
             viewState.firstViewInShelf = algorithmState.firstViewInShelf;
             if (mNotGoneIndex != -1) {
@@ -219,7 +230,7 @@
             }
 
             final float stackEnd = ambientState.getStackY() + ambientState.getStackHeight();
-            viewState.yTranslation = stackEnd - viewState.height;
+            viewState.setYTranslation(stackEnd - viewState.height);
         } else {
             viewState.hidden = true;
             viewState.location = ExpandableViewState.LOCATION_GONE;
@@ -783,7 +794,7 @@
         if (iconState == null) {
             return;
         }
-        iconState.alpha = ICON_ALPHA_INTERPOLATOR.getInterpolation(transitionAmount);
+        iconState.setAlpha(ICON_ALPHA_INTERPOLATOR.getInterpolation(transitionAmount));
         boolean isAppearing = row.isDrawingAppearAnimation() && !row.isInShelf();
         iconState.hidden = isAppearing
                 || (view instanceof ExpandableNotificationRow
@@ -798,12 +809,12 @@
 
         // Fade in icons at shelf start
         // This is important for conversation icons, which are badged and need x reset
-        iconState.xTranslation = mShelfIcons.getActualPaddingStart();
+        iconState.setXTranslation(mShelfIcons.getActualPaddingStart());
 
         final boolean stayingInShelf = row.isInShelf() && !row.isTransformingIntoShelf();
         if (stayingInShelf) {
             iconState.iconAppearAmount = 1.0f;
-            iconState.alpha = 1.0f;
+            iconState.setAlpha(1.0f);
             iconState.hidden = false;
         }
         int backgroundColor = getBackgroundColorWithoutTint();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 039a362..c35c5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -22,6 +22,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.annotation.IntDef;
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.content.Context;
@@ -36,7 +37,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.os.Parcelable;
 import android.os.Trace;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
@@ -60,6 +60,8 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.util.drawable.DrawableSize;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -87,6 +89,10 @@
     public static final int STATE_DOT = 1;
     public static final int STATE_HIDDEN = 2;
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATE_ICON, STATE_DOT, STATE_HIDDEN})
+    public @interface VisibleState { }
+
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -134,6 +140,7 @@
     private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private float mDotRadius;
     private int mStaticDotRadius;
+    @StatusBarIconView.VisibleState
     private int mVisibleState = STATE_ICON;
     private float mIconAppearAmount = 1.0f;
     private ObjectAnimator mIconAppearAnimator;
@@ -551,9 +558,12 @@
         }
     }
 
+    @Override
     public String toString() {
-        return "StatusBarIconView(slot=" + mSlot + " icon=" + mIcon
-            + " notification=" + mNotification + ")";
+        return "StatusBarIconView("
+                + "slot='" + mSlot + " alpha=" + getAlpha() + " icon=" + mIcon
+                + " iconColor=#" + Integer.toHexString(mIconColor)
+                + " notification=" + mNotification + ')';
     }
 
     public StatusBarNotification getNotification() {
@@ -744,11 +754,12 @@
     }
 
     @Override
-    public void setVisibleState(int state) {
+    public void setVisibleState(@StatusBarIconView.VisibleState int state) {
         setVisibleState(state, true /* animate */, null /* endRunnable */);
     }
 
-    public void setVisibleState(int state, boolean animate) {
+    @Override
+    public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
         setVisibleState(state, animate, null);
     }
 
@@ -860,6 +871,7 @@
         return mIconAppearAmount;
     }
 
+    @StatusBarIconView.VisibleState
     public int getVisibleState() {
         return mVisibleState;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 25c6dce..fdad101 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -29,7 +29,6 @@
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -43,7 +42,10 @@
 
 import java.util.ArrayList;
 
-public class StatusBarMobileView extends FrameLayout implements DarkReceiver,
+/**
+ * View group for the mobile icon in the status bar
+ */
+public class StatusBarMobileView extends BaseStatusBarFrameLayout implements DarkReceiver,
         StatusIconDisplayable {
     private static final String TAG = "StatusBarMobileView";
 
@@ -59,7 +61,8 @@
     private ImageView mOut;
     private ImageView mMobile, mMobileType, mMobileRoaming;
     private View mMobileRoamingSpace;
-    private int mVisibleState = -1;
+    @StatusBarIconView.VisibleState
+    private int mVisibleState = STATE_HIDDEN;
     private DualToneHandler mDualToneHandler;
     private boolean mForceHidden;
 
@@ -100,11 +103,6 @@
         super(context, attrs, defStyleAttr);
     }
 
-    public StatusBarMobileView(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
     @Override
     public void getDrawingRect(Rect outRect) {
         super.getDrawingRect(outRect);
@@ -271,7 +269,7 @@
     }
 
     @Override
-    public void setVisibleState(int state, boolean animate) {
+    public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
         if (state == mVisibleState) {
             return;
         }
@@ -312,6 +310,7 @@
     }
 
     @Override
+    @StatusBarIconView.VisibleState
     public int getVisibleState() {
         return mVisibleState;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 5aee62e..decc70d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -40,7 +40,7 @@
 /**
  * Start small: StatusBarWifiView will be able to layout from a WifiIconState
  */
-public class StatusBarWifiView extends BaseStatusBarWifiView implements DarkReceiver {
+public class StatusBarWifiView extends BaseStatusBarFrameLayout implements DarkReceiver {
     private static final String TAG = "StatusBarWifiView";
 
     /// Used to show etc dots
@@ -55,7 +55,8 @@
     private View mAirplaneSpacer;
     private WifiIconState mState;
     private String mSlot;
-    private int mVisibleState = -1;
+    @StatusBarIconView.VisibleState
+    private int mVisibleState = STATE_HIDDEN;
 
     public static StatusBarWifiView fromContext(Context context, String slot) {
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -107,7 +108,7 @@
     }
 
     @Override
-    public void setVisibleState(int state, boolean animate) {
+    public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
         if (state == mVisibleState) {
             return;
         }
@@ -131,6 +132,7 @@
     }
 
     @Override
+    @StatusBarIconView.VisibleState
     public int getVisibleState() {
         return mVisibleState;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
index d541fae..1196211 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
@@ -22,14 +22,32 @@
     String getSlot();
     void setStaticDrawableColor(int color);
     void setDecorColor(int color);
-    default void setVisibleState(int state) {
+
+    /** Sets the visible state that this displayable should be. */
+    default void setVisibleState(@StatusBarIconView.VisibleState int state) {
         setVisibleState(state, false);
     }
-    void setVisibleState(int state, boolean animate);
+
+    /**
+     * Sets the visible state that this displayable should be, and whether the change should
+     * animate.
+     */
+    void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate);
+
+    /** Returns the current visible state of this displayable. */
+    @StatusBarIconView.VisibleState
     int getVisibleState();
+
+    /**
+     * Returns true if this icon should be visible if there's space, and false otherwise.
+     *
+     * Note that this doesn't necessarily mean it *will* be visible. It's possible that there are
+     * more icons than space, in which case this icon might just show a dot or might be completely
+     * hidden. {@link #getVisibleState} will return the icon's actual visible status.
+     */
     boolean isIconVisible();
+
     default boolean isIconBlocked() {
         return false;
     }
 }
-
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 7cd79ca..11e3d17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -26,6 +26,7 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
@@ -130,6 +131,9 @@
             NotifCollection notifCollection,
             @Main DelayableExecutor mainExecutor,
             MediaDataManager mediaDataManager,
+            StatusBarStateController statusBarStateController,
+            SysuiColorExtractor colorExtractor,
+            KeyguardStateController keyguardStateController,
             DumpManager dumpManager) {
         return new NotificationMediaManager(
                 context,
@@ -142,6 +146,9 @@
                 notifCollection,
                 mainExecutor,
                 mediaDataManager,
+                statusBarStateController,
+                colorExtractor,
+                keyguardStateController,
                 dumpManager);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 3eaa988..e129ee4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -1398,7 +1398,7 @@
             throw exception;
         }
 
-        Log.e(TAG, "Allowing " + mConsecutiveReentrantRebuilds
+        Log.wtf(TAG, "Allowing " + mConsecutiveReentrantRebuilds
                 + " consecutive reentrant notification pipeline rebuild(s).", exception);
         mChoreographer.schedule();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 8278b54..ccf6fec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -393,7 +393,7 @@
             val posted = mPostedEntries.compute(entry.key) { _, value ->
                 value?.also { update ->
                     update.wasUpdated = true
-                    update.shouldHeadsUpEver = update.shouldHeadsUpEver || shouldHeadsUpEver
+                    update.shouldHeadsUpEver = shouldHeadsUpEver
                     update.shouldHeadsUpAgain = update.shouldHeadsUpAgain || shouldHeadsUpAgain
                     update.isAlerting = isAlerting
                     update.isBinding = isBinding
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 1aa0295..8e646a3 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
@@ -19,6 +19,8 @@
 import android.service.notification.StatusBarNotification
 import com.android.systemui.ForegroundServiceNotificationListener
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.people.widget.PeopleSpaceWidgetManager
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
 import com.android.systemui.statusbar.NotificationListener
@@ -36,6 +38,7 @@
 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.NotificationMemoryMonitor
 import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
 import com.android.systemui.statusbar.phone.CentralSurfaces
@@ -68,6 +71,8 @@
     private val peopleSpaceWidgetManager: PeopleSpaceWidgetManager,
     private val bubblesOptional: Optional<Bubbles>,
     private val fgsNotifListener: ForegroundServiceNotificationListener,
+    private val memoryMonitor: Lazy<NotificationMemoryMonitor>,
+    private val featureFlags: FeatureFlags
 ) : NotificationsController {
 
     override fun initialize(
@@ -107,6 +112,9 @@
 
         peopleSpaceWidgetManager.attach(notificationListener)
         fgsNotifListener.init()
+        if (featureFlags.isEnabled(Flags.NOTIFICATION_MEMORY_MONITOR_ENABLED)) {
+            memoryMonitor.get().init()
+        }
     }
 
     // TODO: Convert all functions below this line into listeners instead of public methods
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemory.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemory.kt
new file mode 100644
index 0000000..832a739
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemory.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.systemui.statusbar.notification.logging
+
+/** Describes usage of a notification. */
+data class NotificationMemoryUsage(
+    val packageName: String,
+    val notificationId: String,
+    val objectUsage: NotificationObjectUsage,
+)
+
+/**
+ * Describes current memory usage of a [android.app.Notification] object.
+ *
+ * The values are in bytes.
+ */
+data class NotificationObjectUsage(
+    val smallIcon: Int,
+    val largeIcon: Int,
+    val extras: Int,
+    val style: String?,
+    val styleIcon: Int,
+    val bigPicture: Int,
+    val extender: Int,
+    val hasCustomView: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
new file mode 100644
index 0000000..958978e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitor.kt
@@ -0,0 +1,243 @@
+/*
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.logging
+
+import android.app.Notification
+import android.app.Person
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.Log
+import androidx.annotation.WorkerThread
+import androidx.core.util.contains
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/** This class monitors and logs current Notification memory use. */
+@SysUISingleton
+class NotificationMemoryMonitor
+@Inject
+constructor(
+    val notificationPipeline: NotifPipeline,
+    val dumpManager: DumpManager,
+) : Dumpable {
+
+    companion object {
+        private const val TAG = "NotificationMemMonitor"
+        private const val CAR_EXTENSIONS = "android.car.EXTENSIONS"
+        private const val CAR_EXTENSIONS_LARGE_ICON = "large_icon"
+        private const val TV_EXTENSIONS = "android.tv.EXTENSIONS"
+        private const val WEARABLE_EXTENSIONS = "android.wearable.EXTENSIONS"
+        private const val WEARABLE_EXTENSIONS_BACKGROUND = "background"
+    }
+
+    fun init() {
+        Log.d(TAG, "NotificationMemoryMonitor initialized.")
+        dumpManager.registerDumpable(javaClass.simpleName, this)
+    }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        currentNotificationMemoryUse().forEach { use -> pw.println(use.toString()) }
+    }
+
+    @WorkerThread
+    fun currentNotificationMemoryUse(): List<NotificationMemoryUsage> {
+        return notificationMemoryUse(notificationPipeline.allNotifs)
+    }
+
+    /** Returns a list of memory use entries for currently shown notifications. */
+    @WorkerThread
+    fun notificationMemoryUse(
+        notifications: Collection<NotificationEntry>
+    ): List<NotificationMemoryUsage> {
+        return notifications
+            .asSequence()
+            .map { entry ->
+                val packageName = entry.sbn.packageName
+                val notificationObjectUsage =
+                    computeNotificationObjectUse(entry.sbn.notification, hashSetOf())
+                NotificationMemoryUsage(
+                    packageName,
+                    NotificationUtils.logKey(entry.sbn.key),
+                    notificationObjectUsage
+                )
+            }
+            .toList()
+    }
+
+    /**
+     * Computes the estimated memory usage of a given [Notification] object. It'll attempt to
+     * inspect Bitmaps in the object and provide summary of memory usage.
+     */
+    private fun computeNotificationObjectUse(
+        notification: Notification,
+        seenBitmaps: HashSet<Int>
+    ): NotificationObjectUsage {
+        val extras = notification.extras
+        val smallIconUse = computeIconUse(notification.smallIcon, seenBitmaps)
+        val largeIconUse = computeIconUse(notification.getLargeIcon(), seenBitmaps)
+
+        // Collect memory usage of extra styles
+
+        // Big Picture
+        val bigPictureIconUse =
+            computeParcelableUse(extras, Notification.EXTRA_PICTURE_ICON, seenBitmaps) +
+                computeParcelableUse(extras, Notification.EXTRA_LARGE_ICON_BIG, seenBitmaps)
+        val bigPictureUse =
+            computeParcelableUse(extras, Notification.EXTRA_PICTURE, seenBitmaps) +
+                computeParcelableUse(extras, Notification.EXTRA_PICTURE_ICON, seenBitmaps)
+
+        // People
+        val peopleList = extras.getParcelableArrayList<Person>(Notification.EXTRA_PEOPLE_LIST)
+        val peopleUse =
+            peopleList?.sumOf { person -> computeIconUse(person.icon, seenBitmaps) } ?: 0
+
+        // Calling
+        val callingPersonUse =
+            computeParcelableUse(extras, Notification.EXTRA_CALL_PERSON, seenBitmaps)
+        val verificationIconUse =
+            computeParcelableUse(extras, Notification.EXTRA_VERIFICATION_ICON, seenBitmaps)
+
+        // Messages
+        val messages =
+            Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+                extras.getParcelableArray(Notification.EXTRA_MESSAGES)
+            )
+        val messagesUse =
+            messages.sumOf { msg -> computeIconUse(msg.senderPerson?.icon, seenBitmaps) }
+        val historicMessages =
+            Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+                extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES)
+            )
+        val historyicMessagesUse =
+            historicMessages.sumOf { msg -> computeIconUse(msg.senderPerson?.icon, seenBitmaps) }
+
+        // Extenders
+        val carExtender = extras.getBundle(CAR_EXTENSIONS)
+        val carExtenderSize = carExtender?.let { computeBundleSize(it) } ?: 0
+        val carExtenderIcon =
+            computeParcelableUse(carExtender, CAR_EXTENSIONS_LARGE_ICON, seenBitmaps)
+
+        val tvExtender = extras.getBundle(TV_EXTENSIONS)
+        val tvExtenderSize = tvExtender?.let { computeBundleSize(it) } ?: 0
+
+        val wearExtender = extras.getBundle(WEARABLE_EXTENSIONS)
+        val wearExtenderSize = wearExtender?.let { computeBundleSize(it) } ?: 0
+        val wearExtenderBackground =
+            computeParcelableUse(wearExtender, WEARABLE_EXTENSIONS_BACKGROUND, seenBitmaps)
+
+        val style = notification.notificationStyle
+        val hasCustomView = notification.contentView != null || notification.bigContentView != null
+        val extrasSize = computeBundleSize(extras)
+
+        return NotificationObjectUsage(
+            smallIconUse,
+            largeIconUse,
+            extrasSize,
+            style?.simpleName,
+            bigPictureIconUse +
+                peopleUse +
+                callingPersonUse +
+                verificationIconUse +
+                messagesUse +
+                historyicMessagesUse,
+            bigPictureUse,
+            carExtenderSize +
+                carExtenderIcon +
+                tvExtenderSize +
+                wearExtenderSize +
+                wearExtenderBackground,
+            hasCustomView
+        )
+    }
+
+    /**
+     * Calculates size of the bundle data (excluding FDs and other shared objects like ashmem
+     * bitmaps). Can be slow.
+     */
+    private fun computeBundleSize(extras: Bundle): Int {
+        val parcel = Parcel.obtain()
+        try {
+            extras.writeToParcel(parcel, 0)
+            return parcel.dataSize()
+        } finally {
+            parcel.recycle()
+        }
+    }
+
+    /**
+     * Deserializes [Icon], [Bitmap] or [Person] from extras and computes its memory use. Returns 0
+     * if the key does not exist in extras.
+     */
+    private fun computeParcelableUse(extras: Bundle?, key: String, seenBitmaps: HashSet<Int>): Int {
+        return when (val parcelable = extras?.getParcelable<Parcelable>(key)) {
+            is Bitmap -> computeBitmapUse(parcelable, seenBitmaps)
+            is Icon -> computeIconUse(parcelable, seenBitmaps)
+            is Person -> computeIconUse(parcelable.icon, seenBitmaps)
+            else -> 0
+        }
+    }
+
+    /**
+     * Calculates the byte size of bitmaps or data in the Icon object. Returns 0 if the icon is
+     * defined via Uri or a resource.
+     *
+     * @return memory usage in bytes or 0 if the icon is Uri/Resource based
+     */
+    private fun computeIconUse(icon: Icon?, seenBitmaps: HashSet<Int>) =
+        when (icon?.type) {
+            Icon.TYPE_BITMAP -> computeBitmapUse(icon.bitmap, seenBitmaps)
+            Icon.TYPE_ADAPTIVE_BITMAP -> computeBitmapUse(icon.bitmap, seenBitmaps)
+            Icon.TYPE_DATA -> computeDataUse(icon, seenBitmaps)
+            else -> 0
+        }
+
+    /**
+     * Returns the amount of memory a given bitmap is using. If the bitmap reference is part of
+     * seenBitmaps set, this method returns 0 to avoid double counting.
+     *
+     * @return memory usage of the bitmap in bytes
+     */
+    private fun computeBitmapUse(bitmap: Bitmap, seenBitmaps: HashSet<Int>? = null): Int {
+        val refId = System.identityHashCode(bitmap)
+        if (seenBitmaps?.contains(refId) == true) {
+            return 0
+        }
+
+        seenBitmaps?.add(refId)
+        return bitmap.allocationByteCount
+    }
+
+    private fun computeDataUse(icon: Icon, seenBitmaps: HashSet<Int>): Int {
+        val refId = System.identityHashCode(icon.dataBytes)
+        if (seenBitmaps.contains(refId)) {
+            return 0
+        }
+
+        seenBitmaps.add(refId)
+        return icon.dataLength
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
index 9faef1b..5ca13c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -45,11 +45,21 @@
     void logPanelShown(boolean isLockscreen,
             @Nullable List<NotificationEntry> visibleNotifications);
 
+    /**
+     * Log a NOTIFICATION_PANEL_REPORTED statsd event, with
+     * {@link NotificationPanelEvent#NOTIFICATION_DRAG} as the eventID.
+     *
+     * @param draggedNotification the notification that is being dragged
+     */
+    void logNotificationDrag(NotificationEntry draggedNotification);
+
     enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
         @UiEvent(doc = "Notification panel shown from status bar.")
         NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
         @UiEvent(doc = "Notification panel shown from lockscreen.")
-        NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201);
+        NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201),
+        @UiEvent(doc = "Notification was dragged")
+        NOTIFICATION_DRAG(1226);
 
         private final int mId;
         NotificationPanelEvent(int id) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
index 75a6019..9a63228 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.statusbar.notification.logging;
 
+import static com.android.systemui.statusbar.notification.logging.NotificationPanelLogger.NotificationPanelEvent.NOTIFICATION_DRAG;
+
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.nano.Notifications;
 
 import com.google.protobuf.nano.MessageNano;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -38,4 +41,14 @@
                 /* int num_notifications*/ proto.notifications.length,
                 /* byte[] notifications*/ MessageNano.toByteArray(proto));
     }
+
+    @Override
+    public void logNotificationDrag(NotificationEntry draggedNotification) {
+        final Notifications.NotificationList proto = NotificationPanelLogger.toNotificationProto(
+                Collections.singletonList(draggedNotification));
+        SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED,
+                /* int event_id */ NOTIFICATION_DRAG.getId(),
+                /* int num_notifications*/ proto.notifications.length,
+                /* byte[] notifications*/ MessageNano.toByteArray(proto));
+    }
 }
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 6138265..087dc71 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
@@ -1477,6 +1477,20 @@
         }
     }
 
+    /**
+     * Sets the alpha on the content, while leaving the background of the row itself as is.
+     *
+     * @param alpha alpha value to apply to the notification content
+     */
+    public void setContentAlpha(float alpha) {
+        for (NotificationContentView l : mLayouts) {
+            l.setAlpha(alpha);
+        }
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setAlpha(alpha);
+        }
+    }
+
     public void setIsLowPriority(boolean isLowPriority) {
         mIsLowPriority = isLowPriority;
         mPrivateLayout.setIsLowPriority(isLowPriority);
@@ -3362,7 +3376,7 @@
 
         private void handleFixedTranslationZ(ExpandableNotificationRow row) {
             if (row.hasExpandingChild()) {
-                zTranslation = row.getTranslationZ();
+                setZTranslation(row.getTranslationZ());
                 clipTopAmount = row.getClipTopAmount();
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 4939a9c..64f87ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -45,12 +45,17 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.logging.InstanceId;
+import com.android.internal.logging.InstanceIdSequence;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
+import java.util.Collections;
+
 import javax.inject.Inject;
 
 /**
@@ -63,14 +68,17 @@
     private final Context mContext;
     private final HeadsUpManager mHeadsUpManager;
     private final ShadeController mShadeController;
+    private NotificationPanelLogger mNotificationPanelLogger;
 
     @Inject
     public ExpandableNotificationRowDragController(Context context,
             HeadsUpManager headsUpManager,
-            ShadeController shadeController) {
+            ShadeController shadeController,
+            NotificationPanelLogger notificationPanelLogger) {
         mContext = context;
         mHeadsUpManager = headsUpManager;
         mShadeController = shadeController;
+        mNotificationPanelLogger = notificationPanelLogger;
 
         init();
     }
@@ -120,12 +128,16 @@
         dragIntent.putExtra(ClipDescription.EXTRA_PENDING_INTENT, contentIntent);
         dragIntent.putExtra(Intent.EXTRA_USER, android.os.Process.myUserHandle());
         ClipData.Item item = new ClipData.Item(dragIntent);
+        InstanceId instanceId = new InstanceIdSequence(Integer.MAX_VALUE).newInstanceId();
+        item.getIntent().putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, instanceId);
         ClipData dragData = new ClipData(clipDescription, item);
         View.DragShadowBuilder myShadow = new View.DragShadowBuilder(snapshot);
         view.setOnDragListener(getDraggedViewDragListener());
         boolean result = view.startDragAndDrop(dragData, myShadow, null, View.DRAG_FLAG_GLOBAL
                 | View.DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION);
         if (result) {
+            // Log notification drag only if it succeeds
+            mNotificationPanelLogger.logNotificationDrag(enr.getEntry());
             view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
             if (enr.isPinned()) {
                 mHeadsUpManager.releaseAllImmediately();
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 1e09b8a..38f0c55 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
@@ -621,12 +621,12 @@
         // initialize with the default values of the view
         mViewState.height = getIntrinsicHeight();
         mViewState.gone = getVisibility() == View.GONE;
-        mViewState.alpha = 1f;
+        mViewState.setAlpha(1f);
         mViewState.notGoneIndex = -1;
-        mViewState.xTranslation = getTranslationX();
+        mViewState.setXTranslation(getTranslationX());
         mViewState.hidden = false;
-        mViewState.scaleX = getScaleX();
-        mViewState.scaleY = getScaleY();
+        mViewState.setScaleX(getScaleX());
+        mViewState.setScaleY(getScaleY());
         mViewState.inShelf = false;
         mViewState.headsUpIsVisible = false;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index df81c0e..8de0365 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -1986,6 +1986,25 @@
     public void setRemoteInputVisible(boolean remoteInputVisible) {
         mRemoteInputVisible = remoteInputVisible;
         setClipChildren(!remoteInputVisible);
+        setActionsImportanceForAccessibility(
+                remoteInputVisible ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                        : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+    }
+
+    private void setActionsImportanceForAccessibility(int mode) {
+        if (mExpandedChild != null) {
+            setActionsImportanceForAccessibility(mode, mExpandedChild);
+        }
+        if (mHeadsUpChild != null) {
+            setActionsImportanceForAccessibility(mode, mHeadsUpChild);
+        }
+    }
+
+    private void setActionsImportanceForAccessibility(int mode, View child) {
+        View actionsCandidate = child.findViewById(com.android.internal.R.id.actions);
+        if (actionsCandidate != null) {
+            actionsCandidate.setImportantForAccessibility(mode);
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index d77e03f..7b23a56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -583,24 +583,26 @@
             ExpandableViewState childState = child.getViewState();
             int intrinsicHeight = child.getIntrinsicHeight();
             childState.height = intrinsicHeight;
-            childState.yTranslation = yPosition + launchTransitionCompensation;
+            childState.setYTranslation(yPosition + launchTransitionCompensation);
             childState.hidden = false;
             // When the group is expanded, the children cast the shadows rather than the parent
             // so use the parent's elevation here.
-            childState.zTranslation =
-                    (childrenExpandedAndNotAnimating && mEnableShadowOnChildNotifications)
-                    ? parentState.zTranslation
-                    : 0;
+            if (childrenExpandedAndNotAnimating && mEnableShadowOnChildNotifications) {
+                childState.setZTranslation(parentState.getZTranslation());
+            } else {
+                childState.setZTranslation(0);
+            }
             childState.dimmed = parentState.dimmed;
             childState.hideSensitive = parentState.hideSensitive;
             childState.belowSpeedBump = parentState.belowSpeedBump;
             childState.clipTopAmount = 0;
-            childState.alpha = 0;
+            childState.setAlpha(0);
             if (i < firstOverflowIndex) {
-                childState.alpha = showingAsLowPriority() ? expandFactor : 1.0f;
+                childState.setAlpha(showingAsLowPriority() ? expandFactor : 1.0f);
             } else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
-                childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
-                childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
+                childState.setAlpha(
+                        (mActualHeight - childState.getYTranslation()) / childState.height);
+                childState.setAlpha(Math.max(0.0f, Math.min(1.0f, childState.getAlpha())));
             }
             childState.location = parentState.location;
             childState.inShelf = parentState.inShelf;
@@ -621,13 +623,16 @@
                     if (mirrorView.getVisibility() == GONE) {
                         mirrorView = alignView;
                     }
-                    mGroupOverFlowState.alpha = mirrorView.getAlpha();
-                    mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
+                    mGroupOverFlowState.setAlpha(mirrorView.getAlpha());
+                    float yTranslation = mGroupOverFlowState.getYTranslation()
+                            + NotificationUtils.getRelativeYOffset(
                             mirrorView, overflowView);
+                    mGroupOverFlowState.setYTranslation(yTranslation);
                 }
             } else {
-                mGroupOverFlowState.yTranslation += mNotificationHeaderMargin;
-                mGroupOverFlowState.alpha = 0.0f;
+                mGroupOverFlowState.setYTranslation(
+                        mGroupOverFlowState.getYTranslation() + mNotificationHeaderMargin);
+                mGroupOverFlowState.setAlpha(0.0f);
             }
         }
         if (mNotificationHeader != null) {
@@ -635,11 +640,11 @@
                 mHeaderViewState = new ViewState();
             }
             mHeaderViewState.initFrom(mNotificationHeader);
-            mHeaderViewState.zTranslation = childrenExpandedAndNotAnimating
-                    ? parentState.zTranslation
-                    : 0;
-            mHeaderViewState.yTranslation = mCurrentHeaderTranslation;
-            mHeaderViewState.alpha = mHeaderVisibleAmount;
+            mHeaderViewState.setZTranslation(childrenExpandedAndNotAnimating
+                    ? parentState.getZTranslation()
+                    : 0);
+            mHeaderViewState.setYTranslation(mCurrentHeaderTranslation);
+            mHeaderViewState.setAlpha(mHeaderVisibleAmount);
             // The hiding is done automatically by the alpha, otherwise we'll pick it up again
             // in the next frame with the initFrom call above and have an invisible header
             mHeaderViewState.hidden = false;
@@ -711,14 +716,14 @@
             // layout the divider
             View divider = mDividers.get(i);
             tmpState.initFrom(divider);
-            tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
-            float alpha = mChildrenExpanded && viewState.alpha != 0 ? mDividerAlpha : 0;
-            if (mUserLocked && !showingAsLowPriority() && viewState.alpha != 0) {
+            tmpState.setYTranslation(viewState.getYTranslation() - mDividerHeight);
+            float alpha = mChildrenExpanded && viewState.getAlpha() != 0 ? mDividerAlpha : 0;
+            if (mUserLocked && !showingAsLowPriority() && viewState.getAlpha() != 0) {
                 alpha = NotificationUtils.interpolate(0, mDividerAlpha,
-                        Math.min(viewState.alpha, expandFraction));
+                        Math.min(viewState.getAlpha(), expandFraction));
             }
             tmpState.hidden = !dividersVisible;
-            tmpState.alpha = alpha;
+            tmpState.setAlpha(alpha);
             tmpState.applyToView(divider);
             // There is no fake shadow to be drawn on the children
             child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
@@ -790,24 +795,24 @@
             // layout the divider
             View divider = mDividers.get(i);
             tmpState.initFrom(divider);
-            tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
-            float alpha = mChildrenExpanded && viewState.alpha != 0 ? mDividerAlpha : 0;
-            if (mUserLocked && !showingAsLowPriority() && viewState.alpha != 0) {
+            tmpState.setYTranslation(viewState.getYTranslation() - mDividerHeight);
+            float alpha = mChildrenExpanded && viewState.getAlpha() != 0 ? mDividerAlpha : 0;
+            if (mUserLocked && !showingAsLowPriority() && viewState.getAlpha() != 0) {
                 alpha = NotificationUtils.interpolate(0, mDividerAlpha,
-                        Math.min(viewState.alpha, expandFraction));
+                        Math.min(viewState.getAlpha(), expandFraction));
             }
             tmpState.hidden = !dividersVisible;
-            tmpState.alpha = alpha;
+            tmpState.setAlpha(alpha);
             tmpState.animateTo(divider, properties);
             // There is no fake shadow to be drawn on the children
             child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
         }
         if (mOverflowNumber != null) {
             if (mNeverAppliedGroupState) {
-                float alpha = mGroupOverFlowState.alpha;
-                mGroupOverFlowState.alpha = 0;
+                float alpha = mGroupOverFlowState.getAlpha();
+                mGroupOverFlowState.setAlpha(0);
                 mGroupOverFlowState.applyToView(mOverflowNumber);
-                mGroupOverFlowState.alpha = alpha;
+                mGroupOverFlowState.setAlpha(alpha);
                 mNeverAppliedGroupState = false;
             }
             mGroupOverFlowState.animateTo(mOverflowNumber, properties);
@@ -949,7 +954,7 @@
             child.setAlpha(start);
             ViewState viewState = new ViewState();
             viewState.initFrom(child);
-            viewState.alpha = target;
+            viewState.setAlpha(target);
             ALPHA_FADE_IN.setDelay(i * 50);
             viewState.animateTo(child, ALPHA_FADE_IN);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
index bc172ce..0b435fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSection.java
@@ -35,12 +35,12 @@
  * bounds change.
  */
 public class NotificationSection {
-    private @PriorityBucket int mBucket;
-    private View mOwningView;
-    private Rect mBounds = new Rect();
-    private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
-    private Rect mStartAnimationRect = new Rect();
-    private Rect mEndAnimationRect = new Rect();
+    private @PriorityBucket final int mBucket;
+    private final View mOwningView;
+    private final Rect mBounds = new Rect();
+    private final Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
+    private final Rect mStartAnimationRect = new Rect();
+    private final Rect mEndAnimationRect = new Rect();
     private ObjectAnimator mTopAnimator = null;
     private ObjectAnimator mBottomAnimator = null;
     private ExpandableView mFirstVisibleChild;
@@ -277,7 +277,6 @@
                 }
             }
         }
-        top = Math.max(minTopPosition, top);
         ExpandableView lastView = getLastVisibleChild();
         if (lastView != null) {
             float finalTranslationY = ViewState.getFinalTranslationY(lastView);
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 5fbaa51..836cacc 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
@@ -135,7 +135,7 @@
     private static final boolean SPEW = Log.isLoggable(TAG, Log.VERBOSE);
 
     // Delay in milli-seconds before shade closes for clear all.
-    private final int DELAY_BEFORE_SHADE_CLOSE = 200;
+    private static final int DELAY_BEFORE_SHADE_CLOSE = 200;
     private boolean mShadeNeedsToClose = false;
 
     private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
@@ -152,7 +152,7 @@
     private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
     private boolean mKeyguardBypassEnabled;
 
-    private ExpandHelper mExpandHelper;
+    private final ExpandHelper mExpandHelper;
     private NotificationSwipeHelper mSwipeHelper;
     private int mCurrentStackHeight = Integer.MAX_VALUE;
     private final Paint mBackgroundPaint = new Paint();
@@ -165,12 +165,7 @@
 
     private VelocityTracker mVelocityTracker;
     private OverScroller mScroller;
-    /** Last Y position reported by {@link #mScroller}, used to calculate scroll delta. */
-    private int mLastScrollerY;
-    /**
-     * True if the max position was set to a known position on the last call to {@link #mScroller}.
-     */
-    private boolean mIsScrollerBoundSet;
+
     private Runnable mFinishScrollingCallback;
     private int mTouchSlop;
     private float mSlopMultiplier;
@@ -194,7 +189,6 @@
 
     private int mContentHeight;
     private float mIntrinsicContentHeight;
-    private int mCollapsedSize;
     private int mPaddingBetweenElements;
     private int mMaxTopPadding;
     private int mTopPadding;
@@ -210,15 +204,15 @@
     private final StackScrollAlgorithm mStackScrollAlgorithm;
     private final AmbientState mAmbientState;
 
-    private GroupMembershipManager mGroupMembershipManager;
-    private GroupExpansionManager mGroupExpansionManager;
-    private HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>();
-    private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
-    private ArrayList<ExpandableView> mChildrenToRemoveAnimated = new ArrayList<>();
-    private ArrayList<ExpandableView> mChildrenChangingPositions = new ArrayList<>();
-    private HashSet<View> mFromMoreCardAdditions = new HashSet<>();
-    private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
-    private ArrayList<View> mSwipedOutViews = new ArrayList<>();
+    private final GroupMembershipManager mGroupMembershipManager;
+    private final GroupExpansionManager mGroupExpansionManager;
+    private final HashSet<ExpandableView> mChildrenToAddAnimated = new HashSet<>();
+    private final ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
+    private final ArrayList<ExpandableView> mChildrenToRemoveAnimated = new ArrayList<>();
+    private final ArrayList<ExpandableView> mChildrenChangingPositions = new ArrayList<>();
+    private final HashSet<View> mFromMoreCardAdditions = new HashSet<>();
+    private final ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
+    private final ArrayList<View> mSwipedOutViews = new ArrayList<>();
     private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
     private boolean mAnimationsEnabled;
@@ -296,7 +290,7 @@
     private boolean mDisallowDismissInThisMotion;
     private boolean mDisallowScrollingInThisMotion;
     private long mGoToFullShadeDelay;
-    private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
+    private final ViewTreeObserver.OnPreDrawListener mChildrenUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
@@ -309,17 +303,16 @@
     };
     private NotificationStackScrollLogger mLogger;
     private CentralSurfaces mCentralSurfaces;
-    private int[] mTempInt2 = new int[2];
+    private final int[] mTempInt2 = new int[2];
     private boolean mGenerateChildOrderChangedEvent;
-    private HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
-    private HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>();
-    private HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
+    private final HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
+    private final HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>();
+    private final HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
             = new HashSet<>();
-    private boolean mTrackingHeadsUp;
     private boolean mForceNoOverlappingRendering;
     private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
     private boolean mAnimationRunning;
-    private ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
+    private final ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
@@ -327,21 +320,21 @@
             return true;
         }
     };
-    private NotificationSection[] mSections;
+    private final NotificationSection[] mSections;
     private boolean mAnimateNextBackgroundTop;
     private boolean mAnimateNextBackgroundBottom;
     private boolean mAnimateNextSectionBoundsChange;
     private int mBgColor;
     private float mDimAmount;
     private ValueAnimator mDimAnimator;
-    private ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
+    private final ArrayList<ExpandableView> mTmpSortedChildren = new ArrayList<>();
     private final Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
             mDimAnimator = null;
         }
     };
-    private ValueAnimator.AnimatorUpdateListener mDimUpdateListener
+    private final ValueAnimator.AnimatorUpdateListener mDimUpdateListener
             = new ValueAnimator.AnimatorUpdateListener() {
 
         @Override
@@ -351,29 +344,23 @@
     };
     protected ViewGroup mQsHeader;
     // Rect of QsHeader. Kept as a field just to avoid creating a new one each time.
-    private Rect mQsHeaderBound = new Rect();
+    private final Rect mQsHeaderBound = new Rect();
     private boolean mContinuousShadowUpdate;
     private boolean mContinuousBackgroundUpdate;
-    private ViewTreeObserver.OnPreDrawListener mShadowUpdater
+    private final ViewTreeObserver.OnPreDrawListener mShadowUpdater
             = () -> {
                 updateViewShadows();
                 return true;
             };
-    private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater = () -> {
+    private final ViewTreeObserver.OnPreDrawListener mBackgroundUpdater = () -> {
                 updateBackground();
                 return true;
             };
-    private Comparator<ExpandableView> mViewPositionComparator = (view, otherView) -> {
+    private final Comparator<ExpandableView> mViewPositionComparator = (view, otherView) -> {
         float endY = view.getTranslationY() + view.getActualHeight();
         float otherEndY = otherView.getTranslationY() + otherView.getActualHeight();
-        if (endY < otherEndY) {
-            return -1;
-        } else if (endY > otherEndY) {
-            return 1;
-        } else {
-            // The two notifications end at the same location
-            return 0;
-        }
+        // Return zero when the two notifications end at the same location
+        return Float.compare(endY, otherEndY);
     };
     private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
         @Override
@@ -435,16 +422,14 @@
     private int mUpcomingStatusBarState;
     private int mCachedBackgroundColor;
     private boolean mHeadsUpGoingAwayAnimationsAllowed = true;
-    private Runnable mReflingAndAnimateScroll = () -> {
-        animateScroll();
-    };
+    private final Runnable mReflingAndAnimateScroll = this::animateScroll;
     private int mCornerRadius;
     private int mMinimumPaddings;
     private int mQsTilePadding;
     private boolean mSkinnyNotifsInLandscape;
     private int mSidePaddings;
     private final Rect mBackgroundAnimationRect = new Rect();
-    private ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
+    private final ArrayList<BiConsumer<Float, Float>> mExpandedHeightListeners = new ArrayList<>();
     private int mHeadsUpInset;
 
     /**
@@ -479,8 +464,6 @@
     private int mWaterfallTopInset;
     private NotificationStackScrollLayoutController mController;
 
-    private boolean mKeyguardMediaControllorVisible;
-
     /**
      * The clip path used to clip the view in a rounded way.
      */
@@ -501,7 +484,7 @@
     private int mRoundedRectClippingTop;
     private int mRoundedRectClippingBottom;
     private int mRoundedRectClippingRight;
-    private float[] mBgCornerRadii = new float[8];
+    private final float[] mBgCornerRadii = new float[8];
 
     /**
      * Whether stackY should be animated in case the view is getting shorter than the scroll
@@ -527,7 +510,7 @@
     /**
      * Corner radii of the launched notification if it's clipped
      */
-    private float[] mLaunchedNotificationRadii = new float[8];
+    private final float[] mLaunchedNotificationRadii = new float[8];
 
     /**
      * The notification that is being launched currently.
@@ -779,7 +762,7 @@
         y = getLayoutHeight();
         drawDebugInfo(canvas, y, Color.YELLOW, /* label= */ "getLayoutHeight() = " + y);
 
-        y = (int) mMaxLayoutHeight;
+        y = mMaxLayoutHeight;
         drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "mMaxLayoutHeight = " + y);
 
         // The space between mTopPadding and mKeyguardBottomPadding determines the available space
@@ -997,7 +980,6 @@
         mOverflingDistance = configuration.getScaledOverflingDistance();
 
         Resources res = context.getResources();
-        mCollapsedSize = res.getDimensionPixelSize(R.dimen.notification_min_height);
         mGapHeight = res.getDimensionPixelSize(R.dimen.notification_section_divider_height);
         mStackScrollAlgorithm.initView(context);
         mAmbientState.reload(context);
@@ -1256,12 +1238,9 @@
     private void clampScrollPosition() {
         int scrollRange = getScrollRange();
         if (scrollRange < mOwnScrollY && !mAmbientState.isClearAllInProgress()) {
-            boolean animateStackY = false;
-            if (scrollRange < getScrollAmountToScrollBoundary()
-                    && mAnimateStackYForContentHeightChange) {
-                // if the scroll boundary updates the position of the stack,
-                animateStackY = true;
-            }
+            // if the scroll boundary updates the position of the stack,
+            boolean animateStackY = scrollRange < getScrollAmountToScrollBoundary()
+                    && mAnimateStackYForContentHeightChange;
             setOwnScrollY(scrollRange, animateStackY);
         }
     }
@@ -1318,7 +1297,9 @@
                 + mAmbientState.getOverExpansion()
                 - getCurrentOverScrollAmount(false /* top */);
         float fraction = mAmbientState.getExpansionFraction();
-        if (mAmbientState.isBouncerInTransit()) {
+        // If we are on quick settings, we need to quickly hide it to show the bouncer to avoid an
+        // overlap. Otherwise, we maintain the normal fraction for smoothness.
+        if (mAmbientState.isBouncerInTransit() && mQsExpansionFraction > 0f) {
             fraction = BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(fraction);
         }
         final float stackY = MathUtils.lerp(0, endTopPosition, fraction);
@@ -1504,7 +1485,6 @@
         }
 
         if (mAmbientState.isHiddenAtAll()) {
-            clipToOutline = false;
             invalidateOutline();
             if (isFullyHidden()) {
                 setClipBounds(null);
@@ -1782,7 +1762,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
-    private Runnable mReclamp = new Runnable() {
+    private final Runnable mReclamp = new Runnable() {
         @Override
         public void run() {
             int range = getScrollRange();
@@ -3084,11 +3064,8 @@
         int currentIndex = indexOfChild(child);
 
         if (currentIndex == -1) {
-            boolean isTransient = false;
-            if (child instanceof ExpandableNotificationRow
-                    && child.getTransientContainer() != null) {
-                isTransient = true;
-            }
+            boolean isTransient = child instanceof ExpandableNotificationRow
+                    && child.getTransientContainer() != null;
             Log.e(TAG, "Attempting to re-position "
                     + (isTransient ? "transient" : "")
                     + " view {"
@@ -3149,7 +3126,6 @@
     private void generateHeadsUpAnimationEvents() {
         for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
             ExpandableNotificationRow row = eventPair.first;
-            String key = row.getEntry().getKey();
             boolean isHeadsUp = eventPair.second;
             if (isHeadsUp != row.isHeadsUp()) {
                 // For cases where we have a heads up showing and appearing again we shouldn't
@@ -3212,10 +3188,8 @@
 
     @ShadeViewRefactor(RefactorComponent.COORDINATOR)
     private boolean shouldHunAppearFromBottom(ExpandableViewState viewState) {
-        if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
-            return false;
-        }
-        return true;
+        return viewState.getYTranslation() + viewState.height
+                >= mAmbientState.getMaxHeadsUpTranslation();
     }
 
     @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
@@ -4790,7 +4764,6 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setTrackingHeadsUp(ExpandableNotificationRow row) {
         mAmbientState.setTrackedHeadsUpRow(row);
-        mTrackingHeadsUp = row != null;
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -6176,7 +6149,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    private ExpandHelper.Callback mExpandHelperCallback = new ExpandHelper.Callback() {
+    private final ExpandHelper.Callback mExpandHelperCallback = new ExpandHelper.Callback() {
         @Override
         public ExpandableView getChildAtPosition(float touchX, float touchY) {
             return NotificationStackScrollLayout.this.getChildAtPosition(touchX, touchY);
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 843a9ff..5c09d61 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
@@ -56,12 +56,13 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Gefingerpoken;
-import com.android.systemui.R;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -178,6 +179,7 @@
     @Nullable private Boolean mHistoryEnabled;
     private int mBarState;
     private HeadsUpAppearanceController mHeadsUpAppearanceController;
+    private final FeatureFlags mFeatureFlags;
 
     private View mLongPressedView;
 
@@ -639,7 +641,8 @@
             InteractionJankMonitor jankMonitor,
             StackStateLogger stackLogger,
             NotificationStackScrollLogger logger,
-            NotificationStackSizeCalculator notificationStackSizeCalculator) {
+            NotificationStackSizeCalculator notificationStackSizeCalculator,
+            FeatureFlags featureFlags) {
         mStackStateLogger = stackLogger;
         mLogger = logger;
         mAllowLongPress = allowLongPress;
@@ -675,6 +678,7 @@
         mUiEventLogger = uiEventLogger;
         mRemoteInputManager = remoteInputManager;
         mShadeController = shadeController;
+        mFeatureFlags = featureFlags;
         updateResources();
     }
 
@@ -739,9 +743,7 @@
 
         mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
 
-        mFadeNotificationsOnDismiss =  // TODO: this should probably be injected directly
-                mResources.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
-
+        mFadeNotificationsOnDismiss = mFeatureFlags.isEnabled(Flags.NOTIFICATION_DISMISSAL_FADE);
         mNotificationRoundnessManager.setOnRoundingChangedCallback(mView::invalidate);
         mView.addOnExpandedHeightChangedListener(mNotificationRoundnessManager::setExpanded);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 2d2fbe5..ee57411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -185,6 +185,13 @@
         return false;
     }
 
+    @Override
+    protected void updateSwipeProgressAlpha(View animView, float alpha) {
+        if (animView instanceof ExpandableNotificationRow) {
+            ((ExpandableNotificationRow) animView).setContentAlpha(alpha);
+        }
+    }
+
     @VisibleForTesting
     protected void handleMenuRowSwipe(MotionEvent ev, View animView, float velocity,
             NotificationMenuRowPlugin menuRow) {
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 eeed070..8d28f75 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
@@ -134,23 +134,23 @@
 
             if (isHunGoingToShade) {
                 // Keep 100% opacity for heads up notification going to shade.
-                viewState.alpha = 1f;
+                viewState.setAlpha(1f);
             } else if (ambientState.isOnKeyguard()) {
                 // Adjust alpha for wakeup to lockscreen.
-                viewState.alpha = 1f - ambientState.getHideAmount();
+                viewState.setAlpha(1f - ambientState.getHideAmount());
             } else if (ambientState.isExpansionChanging()) {
                 // Adjust alpha for shade open & close.
                 float expansion = ambientState.getExpansionFraction();
-                viewState.alpha = ambientState.isBouncerInTransit()
+                viewState.setAlpha(ambientState.isBouncerInTransit()
                         ? BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansion)
-                        : ShadeInterpolation.getContentAlpha(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);
+                viewState.setAlpha(ShadeInterpolation.getContentAlpha(fractionToShade));
             }
 
             NotificationShelf shelf = ambientState.getShelf();
@@ -166,10 +166,10 @@
                     continue;
                 }
 
-                final float shelfTop = shelfState.yTranslation;
-                final float viewTop = viewState.yTranslation;
+                final float shelfTop = shelfState.getYTranslation();
+                final float viewTop = viewState.getYTranslation();
                 if (viewTop >= shelfTop) {
-                    viewState.alpha = 0;
+                    viewState.setAlpha(0);
                 }
             }
         }
@@ -277,7 +277,7 @@
             if (!child.mustStayOnScreen() || state.headsUpIsVisible) {
                 clipStart = Math.max(drawStart, clipStart);
             }
-            float newYTranslation = state.yTranslation;
+            float newYTranslation = state.getYTranslation();
             float newHeight = state.height;
             float newNotificationEnd = newYTranslation + newHeight;
             boolean isHeadsUp = (child instanceof ExpandableNotificationRow) && child.isPinned();
@@ -322,7 +322,8 @@
             childViewState.hideSensitive = hideSensitive;
             boolean isActivatedChild = activatedChild == child;
             if (dimmed && isActivatedChild) {
-                childViewState.zTranslation += 2.0f * ambientState.getZDistanceBetweenElements();
+                childViewState.setZTranslation(childViewState.getZTranslation()
+                        + 2.0f * ambientState.getZDistanceBetweenElements());
             }
         }
     }
@@ -527,12 +528,12 @@
 
         // Must set viewState.yTranslation _before_ use.
         // Incoming views have yTranslation=0 by default.
-        viewState.yTranslation = algorithmState.mCurrentYPosition;
+        viewState.setYTranslation(algorithmState.mCurrentYPosition);
 
+        float viewEnd = viewState.getYTranslation() + viewState.height + ambientState.getStackY();
         maybeUpdateHeadsUpIsVisible(viewState, ambientState.isShadeExpanded(),
-                view.mustStayOnScreen(), /* topVisible */ viewState.yTranslation >= 0,
-                /* viewEnd */ viewState.yTranslation + viewState.height + ambientState.getStackY(),
-                /* hunMax */ ambientState.getMaxHeadsUpTranslation()
+                view.mustStayOnScreen(), /* topVisible */ viewState.getYTranslation() >= 0,
+                viewEnd, /* hunMax */ ambientState.getMaxHeadsUpTranslation()
         );
         if (view instanceof FooterView) {
             final boolean shadeClosed = !ambientState.isShadeExpanded();
@@ -552,7 +553,7 @@
             if (view instanceof EmptyShadeView) {
                 float fullHeight = ambientState.getLayoutMaxHeight() + mMarginBottom
                         - ambientState.getStackY();
-                viewState.yTranslation = (fullHeight - getMaxAllowedChildHeight(view)) / 2f;
+                viewState.setYTranslation((fullHeight - getMaxAllowedChildHeight(view)) / 2f);
             } else if (view != ambientState.getTrackedHeadsUpRow()) {
                 if (ambientState.isExpansionChanging()) {
                     // We later update shelf state, then hide views below the shelf.
@@ -591,13 +592,13 @@
                 + mPaddingBetweenElements;
 
         setLocation(view.getViewState(), algorithmState.mCurrentYPosition, i);
-        viewState.yTranslation += ambientState.getStackY();
+        viewState.setYTranslation(viewState.getYTranslation() + ambientState.getStackY());
     }
 
     @VisibleForTesting
     void updateViewWithShelf(ExpandableView view, ExpandableViewState viewState, float shelfStart) {
-        viewState.yTranslation = Math.min(viewState.yTranslation, shelfStart);
-        if (viewState.yTranslation >= shelfStart) {
+        viewState.setYTranslation(Math.min(viewState.getYTranslation(), shelfStart));
+        if (viewState.getYTranslation() >= shelfStart) {
             viewState.hidden = !view.isExpandAnimationRunning()
                     && !view.hasExpandingChild();
             viewState.inShelf = true;
@@ -690,9 +691,9 @@
         if (trackedHeadsUpRow != null) {
             ExpandableViewState childState = trackedHeadsUpRow.getViewState();
             if (childState != null) {
-                float endPosition = childState.yTranslation - ambientState.getStackTranslation();
-                childState.yTranslation = MathUtils.lerp(
-                        headsUpTranslation, endPosition, ambientState.getAppearFraction());
+                float endPos = childState.getYTranslation() - ambientState.getStackTranslation();
+                childState.setYTranslation(MathUtils.lerp(
+                        headsUpTranslation, endPos, ambientState.getAppearFraction()));
             }
         }
 
@@ -712,7 +713,7 @@
                 childState.location = ExpandableViewState.LOCATION_FIRST_HUN;
             }
             boolean isTopEntry = topHeadsUpEntry == row;
-            float unmodifiedEndLocation = childState.yTranslation + childState.height;
+            float unmodifiedEndLocation = childState.getYTranslation() + childState.height;
             if (mIsExpanded) {
                 if (row.mustStayOnScreen() && !childState.headsUpIsVisible
                         && !row.showingPulsing()) {
@@ -727,13 +728,14 @@
                 }
             }
             if (row.isPinned()) {
-                childState.yTranslation = Math.max(childState.yTranslation, headsUpTranslation);
+                childState.setYTranslation(
+                        Math.max(childState.getYTranslation(), headsUpTranslation));
                 childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
                 childState.hidden = false;
                 ExpandableViewState topState =
                         topHeadsUpEntry == null ? null : topHeadsUpEntry.getViewState();
                 if (topState != null && !isTopEntry && (!mIsExpanded
-                        || unmodifiedEndLocation > topState.yTranslation + topState.height)) {
+                        || unmodifiedEndLocation > topState.getYTranslation() + topState.height)) {
                     // Ensure that a headsUp doesn't vertically extend further than the heads-up at
                     // the top most z-position
                     childState.height = row.getIntrinsicHeight();
@@ -745,11 +747,12 @@
                 // heads up show full of row's content and any scroll y indicate that the
                 // translationY need to move up the HUN.
                 if (!mIsExpanded && isTopEntry && ambientState.getScrollY() > 0) {
-                    childState.yTranslation -= ambientState.getScrollY();
+                    childState.setYTranslation(
+                            childState.getYTranslation() - ambientState.getScrollY());
                 }
             }
             if (row.isHeadsUpAnimatingAway()) {
-                childState.yTranslation = Math.max(childState.yTranslation, mHeadsUpInset);
+                childState.setYTranslation(Math.max(childState.getYTranslation(), mHeadsUpInset));
                 childState.hidden = false;
             }
         }
@@ -765,13 +768,13 @@
             ExpandableViewState viewState) {
 
         final float newTranslation = Math.max(quickQsOffsetHeight + stackTranslation,
-                viewState.yTranslation);
+                viewState.getYTranslation());
 
         // Transition from collapsed pinned state to fully expanded state
         // when the pinned HUN approaches its actual location (when scrolling back to top).
-        final float distToRealY = newTranslation - viewState.yTranslation;
+        final float distToRealY = newTranslation - viewState.getYTranslation();
         viewState.height = (int) Math.max(viewState.height - distToRealY, collapsedHeight);
-        viewState.yTranslation = newTranslation;
+        viewState.setYTranslation(newTranslation);
     }
 
     // Pin HUN to bottom of expanded QS
@@ -784,10 +787,10 @@
         maxHeadsUpTranslation = Math.min(maxHeadsUpTranslation, maxShelfPosition);
 
         final float bottomPosition = maxHeadsUpTranslation - row.getCollapsedHeight();
-        final float newTranslation = Math.min(childState.yTranslation, bottomPosition);
+        final float newTranslation = Math.min(childState.getYTranslation(), bottomPosition);
         childState.height = (int) Math.min(childState.height, maxHeadsUpTranslation
                 - newTranslation);
-        childState.yTranslation = newTranslation;
+        childState.setYTranslation(newTranslation);
 
         // Animate pinned HUN bottom corners to and from original roundness.
         final float originalCornerRadius =
@@ -859,17 +862,17 @@
         float baseZ = ambientState.getBaseZHeight();
         if (child.mustStayOnScreen() && !childViewState.headsUpIsVisible
                 && !ambientState.isDozingAndNotPulsing(child)
-                && childViewState.yTranslation < ambientState.getTopPadding()
+                && childViewState.getYTranslation() < ambientState.getTopPadding()
                 + ambientState.getStackTranslation()) {
             if (childrenOnTop != 0.0f) {
                 childrenOnTop++;
             } else {
                 float overlap = ambientState.getTopPadding()
-                        + ambientState.getStackTranslation() - childViewState.yTranslation;
+                        + ambientState.getStackTranslation() - childViewState.getYTranslation();
                 childrenOnTop += Math.min(1.0f, overlap / childViewState.height);
             }
-            childViewState.zTranslation = baseZ
-                    + childrenOnTop * zDistanceBetweenElements;
+            childViewState.setZTranslation(baseZ
+                    + childrenOnTop * zDistanceBetweenElements);
         } else if (shouldElevateHun) {
             // In case this is a new view that has never been measured before, we don't want to
             // elevate if we are currently expanded more then the notification
@@ -878,25 +881,28 @@
             float shelfStart = ambientState.getInnerHeight()
                     - shelfHeight + ambientState.getTopPadding()
                     + ambientState.getStackTranslation();
-            float notificationEnd = childViewState.yTranslation + child.getIntrinsicHeight()
+            float notificationEnd = childViewState.getYTranslation() + child.getIntrinsicHeight()
                     + mPaddingBetweenElements;
             if (shelfStart > notificationEnd) {
-                childViewState.zTranslation = baseZ;
+                childViewState.setZTranslation(baseZ);
             } else {
                 float factor = (notificationEnd - shelfStart) / shelfHeight;
+                if (Float.isNaN(factor)) { // Avoid problems when the above is 0/0.
+                    factor = 1.0f;
+                }
                 factor = Math.min(factor, 1.0f);
-                childViewState.zTranslation = baseZ + factor * zDistanceBetweenElements;
+                childViewState.setZTranslation(baseZ + factor * zDistanceBetweenElements);
             }
         } else {
-            childViewState.zTranslation = baseZ;
+            childViewState.setZTranslation(baseZ);
         }
 
         // We need to scrim the notification more from its surrounding content when we are pinned,
         // and we therefore elevate it higher.
         // We can use the headerVisibleAmount for this, since the value nicely goes from 0 to 1 when
         // expanding after which we have a normal elevation again.
-        childViewState.zTranslation += (1.0f - child.getHeaderVisibleAmount())
-                * mPinnedZTranslationExtra;
+        childViewState.setZTranslation(childViewState.getZTranslation()
+                + (1.0f - child.getHeaderVisibleAmount()) * mPinnedZTranslationExtra);
         return childrenOnTop;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 174bf4c..ee72943 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -169,9 +169,9 @@
         adaptDurationWhenGoingToFullShade(child, viewState, wasAdded, animationStaggerCount);
         mAnimationProperties.delay = 0;
         if (wasAdded || mAnimationFilter.hasDelays
-                        && (viewState.yTranslation != child.getTranslationY()
-                        || viewState.zTranslation != child.getTranslationZ()
-                        || viewState.alpha != child.getAlpha()
+                        && (viewState.getYTranslation() != child.getTranslationY()
+                        || viewState.getZTranslation() != child.getTranslationZ()
+                        || viewState.getAlpha() != child.getAlpha()
                         || viewState.height != child.getActualHeight()
                         || viewState.clipTopAmount != child.getClipTopAmount())) {
             mAnimationProperties.delay = mCurrentAdditionalDelay
@@ -191,7 +191,7 @@
                 mAnimationProperties.duration = ANIMATION_DURATION_APPEAR_DISAPPEAR + 50
                         + (long) (100 * longerDurationFactor);
             }
-            child.setTranslationY(viewState.yTranslation + startOffset);
+            child.setTranslationY(viewState.getYTranslation() + startOffset);
         }
     }
 
@@ -400,7 +400,7 @@
                     // travelled
                     ExpandableViewState viewState =
                             ((ExpandableView) event.viewAfterChangingView).getViewState();
-                    translationDirection = ((viewState.yTranslation
+                    translationDirection = ((viewState.getYTranslation()
                             - (ownPosition + actualHeight / 2.0f)) * 2 /
                             actualHeight);
                     translationDirection = Math.max(Math.min(translationDirection, 1.0f),-1.0f);
@@ -433,7 +433,7 @@
                 ExpandableViewState viewState = changingView.getViewState();
                 mTmpState.copyFrom(viewState);
                 if (event.headsUpFromBottom) {
-                    mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
+                    mTmpState.setYTranslation(mHeadsUpAppearHeightBottom);
                 } else {
                     Runnable onAnimationEnd = null;
                     if (loggable) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
index 786de29..d07da38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
+import android.util.Log;
 import android.util.Property;
 import android.view.View;
 import android.view.animation.Interpolator;
@@ -42,7 +43,7 @@
  * A state of a view. This can be used to apply a set of view properties to a view with
  * {@link com.android.systemui.statusbar.notification.stack.StackScrollState} or start
  * animations with {@link com.android.systemui.statusbar.notification.stack.StackStateAnimator}.
-*/
+ */
 public class ViewState implements Dumpable {
 
     /**
@@ -51,6 +52,7 @@
      */
     protected static final AnimationProperties NO_NEW_ANIMATIONS = new AnimationProperties() {
         AnimationFilter mAnimationFilter = new AnimationFilter();
+
         @Override
         public AnimationFilter getAnimationFilter() {
             return mAnimationFilter;
@@ -68,6 +70,7 @@
     private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
     private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
     private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
+    private static final String LOG_TAG = "StackViewState";
 
     private static final AnimatableProperty SCALE_X_PROPERTY
             = new AnimatableProperty() {
@@ -117,35 +120,127 @@
         }
     };
 
-    public float alpha;
-    public float xTranslation;
-    public float yTranslation;
-    public float zTranslation;
     public boolean gone;
     public boolean hidden;
-    public float scaleX = 1.0f;
-    public float scaleY = 1.0f;
+
+    private float mAlpha;
+    private float mXTranslation;
+    private float mYTranslation;
+    private float mZTranslation;
+    private float mScaleX = 1.0f;
+    private float mScaleY = 1.0f;
+
+    public float getAlpha() {
+        return mAlpha;
+    }
+
+    /**
+     * @param alpha View transparency.
+     */
+    public void setAlpha(float alpha) {
+        if (isValidFloat(alpha, "alpha")) {
+            this.mAlpha = alpha;
+        }
+    }
+
+    public float getXTranslation() {
+        return mXTranslation;
+    }
+
+    /**
+     * @param xTranslation x-axis translation value for the animation.
+     */
+    public void setXTranslation(float xTranslation) {
+        if (isValidFloat(xTranslation, "xTranslation")) {
+            this.mXTranslation = xTranslation;
+        }
+    }
+
+    public float getYTranslation() {
+        return mYTranslation;
+    }
+
+    /**
+     * @param yTranslation y-axis translation value for the animation.
+     */
+    public void setYTranslation(float yTranslation) {
+        if (isValidFloat(yTranslation, "yTranslation")) {
+            this.mYTranslation = yTranslation;
+        }
+    }
+
+    public float getZTranslation() {
+        return mZTranslation;
+    }
+
+
+    /**
+     * @param zTranslation z-axis translation value for the animation.
+     */
+    public void setZTranslation(float zTranslation) {
+        if (isValidFloat(zTranslation, "zTranslation")) {
+            this.mZTranslation = zTranslation;
+        }
+    }
+
+    public float getScaleX() {
+        return mScaleX;
+    }
+
+    /**
+     * @param scaleX x-axis scale property for the animation.
+     */
+    public void setScaleX(float scaleX) {
+        if (isValidFloat(scaleX, "scaleX")) {
+            this.mScaleX = scaleX;
+        }
+    }
+
+    public float getScaleY() {
+        return mScaleY;
+    }
+
+    /**
+     * @param scaleY y-axis scale property for the animation.
+     */
+    public void setScaleY(float scaleY) {
+        if (isValidFloat(scaleY, "scaleY")) {
+            this.mScaleY = scaleY;
+        }
+    }
+
+    /**
+     * Checks if {@code value} is a valid float value. If it is not, logs it (using {@code name})
+     * and returns false.
+     */
+    private boolean isValidFloat(float value, String name) {
+        if (Float.isNaN(value)) {
+            Log.wtf(LOG_TAG, "Cannot set property " + name + " to NaN");
+            return false;
+        }
+        return true;
+    }
 
     public void copyFrom(ViewState viewState) {
-        alpha = viewState.alpha;
-        xTranslation = viewState.xTranslation;
-        yTranslation = viewState.yTranslation;
-        zTranslation = viewState.zTranslation;
+        mAlpha = viewState.mAlpha;
+        mXTranslation = viewState.mXTranslation;
+        mYTranslation = viewState.mYTranslation;
+        mZTranslation = viewState.mZTranslation;
         gone = viewState.gone;
         hidden = viewState.hidden;
-        scaleX = viewState.scaleX;
-        scaleY = viewState.scaleY;
+        mScaleX = viewState.mScaleX;
+        mScaleY = viewState.mScaleY;
     }
 
     public void initFrom(View view) {
-        alpha = view.getAlpha();
-        xTranslation = view.getTranslationX();
-        yTranslation = view.getTranslationY();
-        zTranslation = view.getTranslationZ();
+        mAlpha = view.getAlpha();
+        mXTranslation = view.getTranslationX();
+        mYTranslation = view.getTranslationY();
+        mZTranslation = view.getTranslationZ();
         gone = view.getVisibility() == View.GONE;
         hidden = view.getVisibility() == View.INVISIBLE;
-        scaleX = view.getScaleX();
-        scaleY = view.getScaleY();
+        mScaleX = view.getScaleX();
+        mScaleY = view.getScaleY();
     }
 
     /**
@@ -161,51 +256,51 @@
         boolean animatingX = isAnimating(view, TAG_ANIMATOR_TRANSLATION_X);
         if (animatingX) {
             updateAnimationX(view);
-        } else if (view.getTranslationX() != this.xTranslation){
-            view.setTranslationX(this.xTranslation);
+        } else if (view.getTranslationX() != this.mXTranslation) {
+            view.setTranslationX(this.mXTranslation);
         }
 
         // apply yTranslation
         boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y);
         if (animatingY) {
             updateAnimationY(view);
-        } else if (view.getTranslationY() != this.yTranslation) {
-            view.setTranslationY(this.yTranslation);
+        } else if (view.getTranslationY() != this.mYTranslation) {
+            view.setTranslationY(this.mYTranslation);
         }
 
         // apply zTranslation
         boolean animatingZ = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Z);
         if (animatingZ) {
             updateAnimationZ(view);
-        } else if (view.getTranslationZ() != this.zTranslation) {
-            view.setTranslationZ(this.zTranslation);
+        } else if (view.getTranslationZ() != this.mZTranslation) {
+            view.setTranslationZ(this.mZTranslation);
         }
 
         // apply scaleX
         boolean animatingScaleX = isAnimating(view, SCALE_X_PROPERTY);
         if (animatingScaleX) {
-            updateAnimation(view, SCALE_X_PROPERTY, scaleX);
-        } else if (view.getScaleX() != scaleX) {
-            view.setScaleX(scaleX);
+            updateAnimation(view, SCALE_X_PROPERTY, mScaleX);
+        } else if (view.getScaleX() != mScaleX) {
+            view.setScaleX(mScaleX);
         }
 
         // apply scaleY
         boolean animatingScaleY = isAnimating(view, SCALE_Y_PROPERTY);
         if (animatingScaleY) {
-            updateAnimation(view, SCALE_Y_PROPERTY, scaleY);
-        } else if (view.getScaleY() != scaleY) {
-            view.setScaleY(scaleY);
+            updateAnimation(view, SCALE_Y_PROPERTY, mScaleY);
+        } else if (view.getScaleY() != mScaleY) {
+            view.setScaleY(mScaleY);
         }
 
         int oldVisibility = view.getVisibility();
-        boolean becomesInvisible = this.alpha == 0.0f
+        boolean becomesInvisible = this.mAlpha == 0.0f
                 || (this.hidden && (!isAnimating(view) || oldVisibility != View.VISIBLE));
         boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
         if (animatingAlpha) {
             updateAlphaAnimation(view);
-        } else if (view.getAlpha() != this.alpha) {
+        } else if (view.getAlpha() != this.mAlpha) {
             // apply layer type
-            boolean becomesFullyVisible = this.alpha == 1.0f;
+            boolean becomesFullyVisible = this.mAlpha == 1.0f;
             boolean becomesFaded = !becomesInvisible && !becomesFullyVisible;
             if (FadeOptimizedNotification.FADE_LAYER_OPTIMIZATION_ENABLED
                     && view instanceof FadeOptimizedNotification) {
@@ -229,7 +324,7 @@
             }
 
             // apply alpha
-            view.setAlpha(this.alpha);
+            view.setAlpha(this.mAlpha);
         }
 
         // apply visibility
@@ -274,54 +369,55 @@
 
     /**
      * Start an animation to this viewstate
-     * @param child the view to animate
+     *
+     * @param child               the view to animate
      * @param animationProperties the properties of the animation
      */
     public void animateTo(View child, AnimationProperties animationProperties) {
         boolean wasVisible = child.getVisibility() == View.VISIBLE;
-        final float alpha = this.alpha;
+        final float alpha = this.mAlpha;
         if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
                 && !this.gone && !this.hidden) {
             child.setVisibility(View.VISIBLE);
         }
         float childAlpha = child.getAlpha();
-        boolean alphaChanging = this.alpha != childAlpha;
+        boolean alphaChanging = this.mAlpha != childAlpha;
         if (child instanceof ExpandableView) {
             // We don't want views to change visibility when they are animating to GONE
             alphaChanging &= !((ExpandableView) child).willBeGone();
         }
 
         // start translationX animation
-        if (child.getTranslationX() != this.xTranslation) {
+        if (child.getTranslationX() != this.mXTranslation) {
             startXTranslationAnimation(child, animationProperties);
         } else {
             abortAnimation(child, TAG_ANIMATOR_TRANSLATION_X);
         }
 
         // start translationY animation
-        if (child.getTranslationY() != this.yTranslation) {
+        if (child.getTranslationY() != this.mYTranslation) {
             startYTranslationAnimation(child, animationProperties);
         } else {
             abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
         }
 
         // start translationZ animation
-        if (child.getTranslationZ() != this.zTranslation) {
+        if (child.getTranslationZ() != this.mZTranslation) {
             startZTranslationAnimation(child, animationProperties);
         } else {
             abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
         }
 
         // start scaleX animation
-        if (child.getScaleX() != scaleX) {
-            PropertyAnimator.startAnimation(child, SCALE_X_PROPERTY, scaleX, animationProperties);
+        if (child.getScaleX() != mScaleX) {
+            PropertyAnimator.startAnimation(child, SCALE_X_PROPERTY, mScaleX, animationProperties);
         } else {
             abortAnimation(child, SCALE_X_PROPERTY.getAnimatorTag());
         }
 
         // start scaleX animation
-        if (child.getScaleY() != scaleY) {
-            PropertyAnimator.startAnimation(child, SCALE_Y_PROPERTY, scaleY, animationProperties);
+        if (child.getScaleY() != mScaleY) {
+            PropertyAnimator.startAnimation(child, SCALE_Y_PROPERTY, mScaleY, animationProperties);
         } else {
             abortAnimation(child, SCALE_Y_PROPERTY.getAnimatorTag());
         }
@@ -329,7 +425,7 @@
         // start alpha animation
         if (alphaChanging) {
             startAlphaAnimation(child, animationProperties);
-        }  else {
+        } else {
             abortAnimation(child, TAG_ANIMATOR_ALPHA);
         }
     }
@@ -339,9 +435,9 @@
     }
 
     private void startAlphaAnimation(final View child, AnimationProperties properties) {
-        Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
-        Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
-        final float newEndValue = this.alpha;
+        Float previousStartValue = getChildTag(child, TAG_START_ALPHA);
+        Float previousEndValue = getChildTag(child, TAG_END_ALPHA);
+        final float newEndValue = this.mAlpha;
         if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
@@ -426,9 +522,9 @@
     }
 
     private void startZTranslationAnimation(final View child, AnimationProperties properties) {
-        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
-        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
-        float newEndValue = this.zTranslation;
+        Float previousStartValue = getChildTag(child, TAG_START_TRANSLATION_Z);
+        Float previousEndValue = getChildTag(child, TAG_END_TRANSLATION_Z);
+        float newEndValue = this.mZTranslation;
         if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
@@ -487,9 +583,9 @@
     }
 
     private void startXTranslationAnimation(final View child, AnimationProperties properties) {
-        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_X);
-        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_X);
-        float newEndValue = this.xTranslation;
+        Float previousStartValue = getChildTag(child, TAG_START_TRANSLATION_X);
+        Float previousEndValue = getChildTag(child, TAG_END_TRANSLATION_X);
+        float newEndValue = this.mXTranslation;
         if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
@@ -519,7 +615,7 @@
                 child.getTranslationX(), newEndValue);
         Interpolator customInterpolator = properties.getCustomInterpolator(child,
                 View.TRANSLATION_X);
-        Interpolator interpolator =  customInterpolator != null ? customInterpolator
+        Interpolator interpolator = customInterpolator != null ? customInterpolator
                 : Interpolators.FAST_OUT_SLOW_IN;
         animator.setInterpolator(interpolator);
         long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
@@ -553,9 +649,9 @@
     }
 
     private void startYTranslationAnimation(final View child, AnimationProperties properties) {
-        Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
-        Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);
-        float newEndValue = this.yTranslation;
+        Float previousStartValue = getChildTag(child, TAG_START_TRANSLATION_Y);
+        Float previousEndValue = getChildTag(child, TAG_END_TRANSLATION_Y);
+        float newEndValue = this.mYTranslation;
         if (previousEndValue != null && previousEndValue == newEndValue) {
             return;
         }
@@ -585,7 +681,7 @@
                 child.getTranslationY(), newEndValue);
         Interpolator customInterpolator = properties.getCustomInterpolator(child,
                 View.TRANSLATION_Y);
-        Interpolator interpolator =  customInterpolator != null ? customInterpolator
+        Interpolator interpolator = customInterpolator != null ? customInterpolator
                 : Interpolators.FAST_OUT_SLOW_IN;
         animator.setInterpolator(interpolator);
         long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
@@ -644,7 +740,7 @@
     /**
      * Cancel the previous animator and get the duration of the new animation.
      *
-     * @param duration the new duration
+     * @param duration         the new duration
      * @param previousAnimator the animator which was running before
      * @return the new duration
      */
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 f37243a..fa7bfae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -416,6 +416,9 @@
 
     void endAffordanceLaunch();
 
+    /** Should the keyguard be hidden immediately in response to a back press/gesture. */
+    boolean shouldKeyguardHideImmediately();
+
     boolean onBackPressed();
 
     boolean onSpacePressed();
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 0b63bbf..01a92b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -3312,19 +3312,23 @@
         mNotificationPanelViewController.onAffordanceLaunchEnded();
     }
 
+    /**
+     * Returns whether the keyguard should hide immediately (as opposed to via an animation).
+     * Non-scrimmed bouncers have a special animation tied to the notification panel expansion.
+     * @return whether the keyguard should be immediately hidden.
+     */
     @Override
-    public boolean onBackPressed() {
+    public boolean shouldKeyguardHideImmediately() {
         final boolean isScrimmedBouncer =
                 mScrimController.getState() == ScrimState.BOUNCER_SCRIMMED;
         final boolean isBouncerOverDream = isBouncerShowingOverDream();
+        return (isScrimmedBouncer || isBouncerOverDream);
+    }
 
-        if (mStatusBarKeyguardViewManager.onBackPressed(
-                isScrimmedBouncer || isBouncerOverDream /* hideImmediately */)) {
-            if (isScrimmedBouncer || isBouncerOverDream) {
-                mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
-            } else {
-                mNotificationPanelViewController.expandWithoutQs();
-            }
+    @Override
+    public boolean onBackPressed() {
+        if (mStatusBarKeyguardViewManager.canHandleBackPressed()) {
+            mStatusBarKeyguardViewManager.onBackPressed(false /* unused */);
             return true;
         }
         if (mNotificationPanelViewController.isQsCustomizing()) {
@@ -3339,7 +3343,7 @@
             return true;
         }
         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
-                && !isBouncerOverDream) {
+                && !isBouncerShowingOverDream()) {
             if (mNotificationPanelViewController.canPanelBeCollapsed()) {
                 mShadeController.animateCollapsePanels();
             }
@@ -4453,10 +4457,11 @@
                     Trace.beginSection("CentralSurfaces#updateDozing");
                     mDozing = isDozing;
 
-                    // Collapse the notification panel if open
                     boolean dozingAnimated = mDozeServiceHost.getDozingRequested()
                             && mDozeParameters.shouldControlScreenOff();
-                    mNotificationPanelViewController.resetViews(dozingAnimated);
+                    // resetting views is already done when going into doze, there's no need to
+                    // reset them again when we're waking up
+                    mNotificationPanelViewController.resetViews(dozingAnimated && isDozing);
 
                     updateQsExpansionEnabled();
                     mKeyguardViewMediator.setDozing(mDozing);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 54d39fd..de7b152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -93,13 +93,13 @@
     private boolean mControlScreenOffAnimation;
     private boolean mIsQuickPickupEnabled;
 
-    private boolean mKeyguardShowing;
+    private boolean mKeyguardVisible;
     @VisibleForTesting
     final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    mKeyguardShowing = showing;
+                public void onKeyguardVisibilityChanged(boolean visible) {
+                    mKeyguardVisible = visible;
                     updateControlScreenOff();
                 }
 
@@ -293,7 +293,7 @@
     public void updateControlScreenOff() {
         if (!getDisplayNeedsBlanking()) {
             final boolean controlScreenOff =
-                    getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff());
+                    getAlwaysOn() && (mKeyguardVisible || shouldControlUnlockedScreenOff());
             setControlScreenOffAnimation(controlScreenOff);
         }
     }
@@ -348,7 +348,7 @@
     }
 
     private boolean willAnimateFromLockScreenToAod() {
-        return getAlwaysOn() && mKeyguardShowing;
+        return getAlwaysOn() && mKeyguardVisible;
     }
 
     private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 7de4668..0067316 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -18,7 +18,6 @@
 
 import android.annotation.NonNull;
 import android.os.Handler;
-import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.dagger.SysUISingleton;
@@ -34,9 +33,6 @@
  */
 @SysUISingleton
 public class DozeScrimController implements StateListener {
-    private static final String TAG = "DozeScrimController";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
     private final DozeLog mDozeLog;
     private final DozeParameters mDozeParameters;
     private final Handler mHandler = new Handler();
@@ -44,28 +40,26 @@
     private boolean mDozing;
     private DozeHost.PulseCallback mPulseCallback;
     private int mPulseReason;
-    private boolean mFullyPulsing;
 
     private final ScrimController.Callback mScrimCallback = new ScrimController.Callback() {
         @Override
         public void onDisplayBlanked() {
-            if (DEBUG) {
-                Log.d(TAG, "Pulse in, mDozing=" + mDozing + " mPulseReason="
-                        + DozeLog.reasonToString(mPulseReason));
-            }
             if (!mDozing) {
+                mDozeLog.tracePulseDropped("onDisplayBlanked - not dozing");
                 return;
             }
 
-            // Signal that the pulse is ready to turn the screen on and draw.
-            pulseStarted();
+            if (mPulseCallback != null) {
+                // Signal that the pulse is ready to turn the screen on and draw.
+                mDozeLog.tracePulseStart(mPulseReason);
+                mPulseCallback.onPulseStarted();
+            }
         }
 
         @Override
         public void onFinished() {
-            if (DEBUG) {
-                Log.d(TAG, "Pulse in finished, mDozing=" + mDozing);
-            }
+            mDozeLog.tracePulseEvent("scrimCallback-onFinished", mDozing, mPulseReason);
+
             if (!mDozing) {
                 return;
             }
@@ -78,7 +72,6 @@
                 mHandler.postDelayed(mPulseOutExtended,
                         mDozeParameters.getPulseVisibleDurationExtended());
             }
-            mFullyPulsing = true;
         }
 
         /**
@@ -118,19 +111,14 @@
         }
 
         if (!mDozing || mPulseCallback != null) {
-            if (DEBUG) {
-                Log.d(TAG, "Pulse suppressed. Dozing: " + mDozeParameters + " had callback? "
-                        + (mPulseCallback != null));
-            }
             // Pulse suppressed.
             callback.onPulseFinished();
             if (!mDozing) {
-                mDozeLog.tracePulseDropped("device isn't dozing");
+                mDozeLog.tracePulseDropped("pulse - device isn't dozing");
             } else {
-                mDozeLog.tracePulseDropped("already has pulse callback mPulseCallback="
+                mDozeLog.tracePulseDropped("pulse - already has pulse callback mPulseCallback="
                         + mPulseCallback);
             }
-
             return;
         }
 
@@ -141,9 +129,7 @@
     }
 
     public void pulseOutNow() {
-        if (mPulseCallback != null && mFullyPulsing) {
-            mPulseOut.run();
-        }
+        mPulseOut.run();
     }
 
     public boolean isPulsing() {
@@ -168,24 +154,16 @@
 
     private void cancelPulsing() {
         if (mPulseCallback != null) {
-            if (DEBUG) Log.d(TAG, "Cancel pulsing");
-            mFullyPulsing = false;
+            mDozeLog.tracePulseEvent("cancel", mDozing, mPulseReason);
             mHandler.removeCallbacks(mPulseOut);
             mHandler.removeCallbacks(mPulseOutExtended);
             pulseFinished();
         }
     }
 
-    private void pulseStarted() {
-        mDozeLog.tracePulseStart(mPulseReason);
-        if (mPulseCallback != null) {
-            mPulseCallback.onPulseStarted();
-        }
-    }
-
     private void pulseFinished() {
-        mDozeLog.tracePulseFinish();
         if (mPulseCallback != null) {
+            mDozeLog.tracePulseFinish();
             mPulseCallback.onPulseFinished();
             mPulseCallback = null;
         }
@@ -202,10 +180,9 @@
     private final Runnable mPulseOut = new Runnable() {
         @Override
         public void run() {
-            mFullyPulsing = false;
             mHandler.removeCallbacks(mPulseOut);
             mHandler.removeCallbacks(mPulseOutExtended);
-            if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
+            mDozeLog.tracePulseEvent("out", mDozing, mPulseReason);
             if (!mDozing) return;
             pulseFinished();
         }
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 24ce5e9..5196e10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -36,7 +36,6 @@
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.NotificationShadeWindowViewController;
@@ -48,6 +47,7 @@
 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.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.util.Assert;
 
 import java.util.ArrayList;
@@ -80,7 +80,6 @@
     private final BatteryController mBatteryController;
     private final ScrimController mScrimController;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
-    private final KeyguardViewMediator mKeyguardViewMediator;
     private final Lazy<AssistManager> mAssistManagerLazy;
     private final DozeScrimController mDozeScrimController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -95,6 +94,7 @@
     private View mAmbientIndicationContainer;
     private CentralSurfaces mCentralSurfaces;
     private boolean mAlwaysOnSuppressed;
+    private boolean mPulsePending;
 
     @Inject
     public DozeServiceHost(DozeLog dozeLog, PowerManager powerManager,
@@ -104,7 +104,6 @@
             HeadsUpManagerPhone headsUpManagerPhone, BatteryController batteryController,
             ScrimController scrimController,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
-            KeyguardViewMediator keyguardViewMediator,
             Lazy<AssistManager> assistManagerLazy,
             DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
             PulseExpansionHandler pulseExpansionHandler,
@@ -122,7 +121,6 @@
         mBatteryController = batteryController;
         mScrimController = scrimController;
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
-        mKeyguardViewMediator = keyguardViewMediator;
         mAssistManagerLazy = assistManagerLazy;
         mDozeScrimController = dozeScrimController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -131,6 +129,7 @@
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
         mAuthController = authController;
         mNotificationIconAreaController = notificationIconAreaController;
+        mHeadsUpManagerPhone.addListener(mOnHeadsUpChangedListener);
     }
 
     // TODO: we should try to not pass status bar in here if we can avoid it.
@@ -246,7 +245,7 @@
         mDozeScrimController.pulse(new PulseCallback() {
             @Override
             public void onPulseStarted() {
-                callback.onPulseStarted();
+                callback.onPulseStarted(); // requestState(DozeMachine.State.DOZE_PULSING)
                 mCentralSurfaces.updateNotificationPanelTouchState();
                 setPulsing(true);
             }
@@ -254,7 +253,7 @@
             @Override
             public void onPulseFinished() {
                 mPulsing = false;
-                callback.onPulseFinished();
+                callback.onPulseFinished(); // requestState(DozeMachine.State.DOZE_PULSE_DONE)
                 mCentralSurfaces.updateNotificationPanelTouchState();
                 mScrimController.setWakeLockScreenSensorActive(false);
                 setPulsing(false);
@@ -338,9 +337,8 @@
 
     @Override
     public void stopPulsing() {
-        if (mDozeScrimController.isPulsing()) {
-            mDozeScrimController.pulseOutNow();
-        }
+        setPulsePending(false); // prevent any pending pulses from continuing
+        mDozeScrimController.pulseOutNow();
     }
 
     @Override
@@ -451,6 +449,16 @@
         }
     }
 
+    @Override
+    public boolean isPulsePending() {
+        return mPulsePending;
+    }
+
+    @Override
+    public void setPulsePending(boolean isPulsePending) {
+        mPulsePending = isPulsePending;
+    }
+
     /**
      * Whether always-on-display is being suppressed. This does not affect wakeup gestures like
      * pickup and tap.
@@ -458,4 +466,22 @@
     public boolean isAlwaysOnSuppressed() {
         return mAlwaysOnSuppressed;
     }
+
+    final OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() {
+        @Override
+        public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
+            if (mStatusBarStateController.isDozing() && isHeadsUp) {
+                entry.setPulseSuppressed(false);
+                fireNotificationPulse(entry);
+                if (isPulsing()) {
+                    mDozeScrimController.cancelPendingPulseTimeout();
+                }
+            }
+            if (!isHeadsUp && !mHeadsUpManagerPhone.hasNotifications()) {
+                // There are no longer any notifications to show.  We should end the
+                // pulse now.
+                stopPulsing();
+            }
+        }
+    };
 }
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 b58dbe2..e3e8572 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -88,7 +88,7 @@
             updateListeningState()
         }
 
-        override fun onKeyguardVisibilityChanged(showing: Boolean) {
+        override fun onKeyguardVisibilityChanged(visible: Boolean) {
             updateListeningState()
         }
     }
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 ce2c9c2..14cebf4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -40,6 +40,7 @@
 import com.android.keyguard.CarrierTextController;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardLogger;
 import com.android.systemui.R;
 import com.android.systemui.animation.Interpolators;
 import com.android.systemui.battery.BatteryMeterViewController;
@@ -116,6 +117,7 @@
     private final CommandQueue mCommandQueue;
     private final Executor mMainExecutor;
     private final Object mLock = new Object();
+    private final KeyguardLogger mLogger;
 
     private final ConfigurationController.ConfigurationListener mConfigurationListener =
             new ConfigurationController.ConfigurationListener() {
@@ -185,8 +187,8 @@
                 }
 
                 @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    if (showing) {
+                public void onKeyguardVisibilityChanged(boolean visible) {
+                    if (visible) {
                         updateUserSwitcher();
                     }
                 }
@@ -279,7 +281,8 @@
             StatusBarUserInfoTracker statusBarUserInfoTracker,
             SecureSettings secureSettings,
             CommandQueue commandQueue,
-            @Main Executor mainExecutor
+            @Main Executor mainExecutor,
+            KeyguardLogger logger
     ) {
         super(view);
         mCarrierTextController = carrierTextController;
@@ -304,6 +307,7 @@
         mSecureSettings = secureSettings;
         mCommandQueue = commandQueue;
         mMainExecutor = mainExecutor;
+        mLogger = logger;
 
         mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
         mKeyguardStateController.addCallback(
@@ -352,8 +356,8 @@
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
         mDisableStateTracker.startTracking(mCommandQueue, mView.getDisplay().getDisplayId());
         if (mTintedIconManager == null) {
-            mTintedIconManager =
-                    mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
+            mTintedIconManager = mTintedIconManagerFactory.create(
+                    mView.findViewById(R.id.statusIcons), StatusBarLocation.KEYGUARD);
             mTintedIconManager.setBlockList(getBlockedIcons());
             mStatusBarIconController.addIconGroup(mTintedIconManager);
         }
@@ -430,6 +434,7 @@
 
     /** Animate the keyguard status bar in. */
     public void animateKeyguardStatusBarIn() {
+        mLogger.d("animating status bar in");
         if (mDisableStateTracker.isDisabled()) {
             // If our view is disabled, don't allow us to animate in.
             return;
@@ -445,6 +450,7 @@
 
     /** Animate the keyguard status bar out. */
     public void animateKeyguardStatusBarOut(long startDelay, long duration) {
+        mLogger.d("animating status bar out");
         ValueAnimator anim = ValueAnimator.ofFloat(mView.getAlpha(), 0f);
         anim.addUpdateListener(mAnimatorUpdateListener);
         anim.setStartDelay(startDelay);
@@ -481,6 +487,9 @@
             newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
                     * mKeyguardStatusBarAnimateAlpha
                     * (1.0f - mKeyguardHeadsUpShowingAmount);
+            if (newAlpha != mView.getAlpha() && (newAlpha == 0 || newAlpha == 1)) {
+                mLogger.logStatusBarCalculatedAlpha(newAlpha);
+            }
         }
 
         boolean hideForBypass =
@@ -503,6 +512,10 @@
         if (mDisableStateTracker.isDisabled()) {
             visibility = View.INVISIBLE;
         }
+        if (visibility != mView.getVisibility()) {
+            mLogger.logStatusBarAlphaVisibility(visibility, alpha,
+                    StatusBarState.toString(mStatusBarState));
+        }
         mView.setAlpha(alpha);
         mView.setVisibility(visibility);
     }
@@ -596,6 +609,8 @@
         pw.println("KeyguardStatusBarView:");
         pw.println("  mBatteryListening: " + mBatteryListening);
         pw.println("  mExplicitAlpha: " + mExplicitAlpha);
+        pw.println("  alpha: " + mView.getAlpha());
+        pw.println("  visibility: " + mView.getVisibility());
         mView.dump(pw, args);
     }
 
@@ -605,6 +620,10 @@
      * @param alpha a value between 0 and 1. -1 if the value is to be reset/ignored.
      */
     public void setAlpha(float alpha) {
+        if (mExplicitAlpha != alpha && (mExplicitAlpha == -1 || alpha == -1)) {
+            // logged if value changed to ignored or from ignored
+            mLogger.logStatusBarExplicitAlpha(alpha);
+        }
         mExplicitAlpha = alpha;
         updateViewState();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 7b8c5fc..9767103 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -211,11 +211,11 @@
             canvas.drawLine(end, 0, end, height, paint);
 
             paint.setColor(Color.GREEN);
-            int lastIcon = (int) mLastVisibleIconState.xTranslation;
+            int lastIcon = (int) mLastVisibleIconState.getXTranslation();
             canvas.drawLine(lastIcon, 0, lastIcon, height, paint);
 
             if (mFirstVisibleIconState != null) {
-                int firstIcon = (int) mFirstVisibleIconState.xTranslation;
+                int firstIcon = (int) mFirstVisibleIconState.getXTranslation();
                 canvas.drawLine(firstIcon, 0, firstIcon, height, paint);
             }
 
@@ -278,6 +278,15 @@
         }
     }
 
+    @Override
+    public String toString() {
+        return "NotificationIconContainer("
+                + "dozing=" + mDozing + " onLockScreen=" + mOnLockScreen
+                + " inNotificationIconShelf=" + mInNotificationIconShelf
+                + " speedBumpIndex=" + mSpeedBumpIndex
+                + " themedTextColorPrimary=#" + Integer.toHexString(mThemedTextColorPrimary) + ')';
+    }
+
     @VisibleForTesting
     public void setIconSize(int size) {
         mIconSize = size;
@@ -404,7 +413,7 @@
             View view = getChildAt(i);
             ViewState iconState = mIconStates.get(view);
             iconState.initFrom(view);
-            iconState.alpha = mIsolatedIcon == null || view == mIsolatedIcon ? 1.0f : 0.0f;
+            iconState.setAlpha(mIsolatedIcon == null || view == mIsolatedIcon ? 1.0f : 0.0f);
             iconState.hidden = false;
         }
     }
@@ -458,7 +467,7 @@
                 // We only modify the xTranslation if it's fully inside of the container
                 // since during the transition to the shelf, the translations are controlled
                 // from the outside
-                iconState.xTranslation = translationX;
+                iconState.setXTranslation(translationX);
             }
             if (mFirstVisibleIconState == null) {
                 mFirstVisibleIconState = iconState;
@@ -492,7 +501,7 @@
                 View view = getChildAt(i);
                 IconState iconState = mIconStates.get(view);
                 int dotWidth = mStaticDotDiameter + mDotPadding;
-                iconState.xTranslation = translationX;
+                iconState.setXTranslation(translationX);
                 if (mNumDots < MAX_DOTS) {
                     if (mNumDots == 0 && iconState.iconAppearAmount < 0.8f) {
                         iconState.visibleState = StatusBarIconView.STATE_ICON;
@@ -516,7 +525,8 @@
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
                 IconState iconState = mIconStates.get(view);
-                iconState.xTranslation = getWidth() - iconState.xTranslation - view.getWidth();
+                iconState.setXTranslation(
+                        getWidth() - iconState.getXTranslation() - view.getWidth());
             }
         }
         if (mIsolatedIcon != null) {
@@ -524,8 +534,8 @@
             if (iconState != null) {
                 // Most of the time the icon isn't yet added when this is called but only happening
                 // later
-                iconState.xTranslation = mIsolatedIconLocation.left - mAbsolutePosition[0]
-                        - (1 - mIsolatedIcon.getIconScale()) * mIsolatedIcon.getWidth() / 2.0f;
+                iconState.setXTranslation(mIsolatedIconLocation.left - mAbsolutePosition[0]
+                        - (1 - mIsolatedIcon.getIconScale()) * mIsolatedIcon.getWidth() / 2.0f);
                 iconState.visibleState = StatusBarIconView.STATE_ICON;
             }
         }
@@ -600,8 +610,10 @@
             return 0;
         }
 
-        int translation = (int) (isLayoutRtl() ? getWidth() - mLastVisibleIconState.xTranslation
-                : mLastVisibleIconState.xTranslation + mIconSize);
+        int translation = (int) (isLayoutRtl()
+                ? getWidth() - mLastVisibleIconState.getXTranslation()
+                : mLastVisibleIconState.getXTranslation() + mIconSize);
+
         // There's a chance that last translation goes beyond the edge maybe
         return Math.min(getWidth(), translation);
     }
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 4d1c361..9f93223 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1534,7 +1534,7 @@
     private class KeyguardVisibilityCallback extends KeyguardUpdateMonitorCallback {
 
         @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
+        public void onKeyguardVisibilityChanged(boolean visible) {
             mNeedsDrawableColorUpdate = true;
             scheduleUpdate();
         }
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 ae201e3..5512bed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeadsUpChangeListener.java
@@ -21,8 +21,6 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.init.NotificationsController;
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.window.StatusBarWindowController;
@@ -41,9 +39,6 @@
     private final HeadsUpManagerPhone mHeadsUpManager;
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
-    private final NotificationsController mNotificationsController;
-    private final DozeServiceHost mDozeServiceHost;
-    private final DozeScrimController mDozeScrimController;
 
     @Inject
     StatusBarHeadsUpChangeListener(
@@ -53,10 +48,7 @@
             KeyguardBypassController keyguardBypassController,
             HeadsUpManagerPhone headsUpManager,
             StatusBarStateController statusBarStateController,
-            NotificationRemoteInputManager notificationRemoteInputManager,
-            NotificationsController notificationsController,
-            DozeServiceHost dozeServiceHost,
-            DozeScrimController dozeScrimController) {
+            NotificationRemoteInputManager notificationRemoteInputManager) {
 
         mNotificationShadeWindowController = notificationShadeWindowController;
         mStatusBarWindowController = statusBarWindowController;
@@ -65,9 +57,6 @@
         mHeadsUpManager = headsUpManager;
         mStatusBarStateController = statusBarStateController;
         mNotificationRemoteInputManager = notificationRemoteInputManager;
-        mNotificationsController = notificationsController;
-        mDozeServiceHost = dozeServiceHost;
-        mDozeScrimController = dozeScrimController;
     }
 
     @Override
@@ -117,20 +106,4 @@
             }
         }
     }
-
-    @Override
-    public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
-        if (mStatusBarStateController.isDozing() && isHeadsUp) {
-            entry.setPulseSuppressed(false);
-            mDozeServiceHost.fireNotificationPulse(entry);
-            if (mDozeServiceHost.isPulsing()) {
-                mDozeScrimController.cancelPendingPulseTimeout();
-            }
-        }
-        if (!isHeadsUp && !mHeadsUpManager.hasNotifications()) {
-            // There are no longer any notifications to show.  We should end the
-            //pulse now.
-            mDozeScrimController.pulseOutNow();
-        }
-    }
 }
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 bd99713..ece7ee0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -16,6 +16,7 @@
 
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_ICON;
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE;
+import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_MOBILE_NEW;
 import static com.android.systemui.statusbar.phone.StatusBarIconHolder.TYPE_WIFI;
 
 import android.annotation.Nullable;
@@ -38,7 +39,7 @@
 import com.android.systemui.demomode.DemoModeCommandReceiver;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
-import com.android.systemui.statusbar.BaseStatusBarWifiView;
+import com.android.systemui.statusbar.BaseStatusBarFrameLayout;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarMobileView;
 import com.android.systemui.statusbar.StatusBarWifiView;
@@ -48,6 +49,10 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconsBinder;
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
 import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel;
 import com.android.systemui.util.Assert;
@@ -56,7 +61,6 @@
 import java.util.List;
 
 import javax.inject.Inject;
-import javax.inject.Provider;
 
 public interface StatusBarIconController {
 
@@ -85,6 +89,12 @@
     void setMobileIcons(String slot, List<MobileIconState> states);
 
     /**
+     * This method completely replaces {@link #setMobileIcons} with the information from the new
+     * mobile data pipeline. Icons will automatically keep their state up to date, so we don't have
+     * to worry about funneling MobileIconState objects through anymore.
+     */
+    void setNewMobileIconSubIds(List<Integer> subIds);
+    /**
      * Display the no calling & SMS icons.
      */
     void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states);
@@ -139,13 +149,17 @@
 
         public DarkIconManager(
                 LinearLayout linearLayout,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
+                WifiViewModel wifiViewModel,
+                MobileUiAdapter mobileUiAdapter,
                 MobileContextProvider mobileContextProvider,
                 DarkIconDispatcher darkIconDispatcher) {
             super(linearLayout,
+                    location,
                     statusBarPipelineFlags,
-                    wifiViewModelProvider,
+                    wifiViewModel,
+                    mobileUiAdapter,
                     mobileContextProvider);
             mIconHPadding = mContext.getResources().getDimensionPixelSize(
                     R.dimen.status_bar_icon_padding);
@@ -204,27 +218,32 @@
         @SysUISingleton
         public static class Factory {
             private final StatusBarPipelineFlags mStatusBarPipelineFlags;
-            private final Provider<WifiViewModel> mWifiViewModelProvider;
+            private final WifiViewModel mWifiViewModel;
             private final MobileContextProvider mMobileContextProvider;
+            private final MobileUiAdapter mMobileUiAdapter;
             private final DarkIconDispatcher mDarkIconDispatcher;
 
             @Inject
             public Factory(
                     StatusBarPipelineFlags statusBarPipelineFlags,
-                    Provider<WifiViewModel> wifiViewModelProvider,
+                    WifiViewModel wifiViewModel,
                     MobileContextProvider mobileContextProvider,
+                    MobileUiAdapter mobileUiAdapter,
                     DarkIconDispatcher darkIconDispatcher) {
                 mStatusBarPipelineFlags = statusBarPipelineFlags;
-                mWifiViewModelProvider = wifiViewModelProvider;
+                mWifiViewModel = wifiViewModel;
                 mMobileContextProvider = mobileContextProvider;
+                mMobileUiAdapter = mobileUiAdapter;
                 mDarkIconDispatcher = darkIconDispatcher;
             }
 
-            public DarkIconManager create(LinearLayout group) {
+            public DarkIconManager create(LinearLayout group, StatusBarLocation location) {
                 return new DarkIconManager(
                         group,
+                        location,
                         mStatusBarPipelineFlags,
-                        mWifiViewModelProvider,
+                        mWifiViewModel,
+                        mMobileUiAdapter,
                         mMobileContextProvider,
                         mDarkIconDispatcher);
             }
@@ -239,12 +258,17 @@
 
         public TintedIconManager(
                 ViewGroup group,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
-                MobileContextProvider mobileContextProvider) {
+                WifiViewModel wifiViewModel,
+                MobileUiAdapter mobileUiAdapter,
+                MobileContextProvider mobileContextProvider
+        ) {
             super(group,
+                    location,
                     statusBarPipelineFlags,
-                    wifiViewModelProvider,
+                    wifiViewModel,
+                    mobileUiAdapter,
                     mobileContextProvider);
         }
 
@@ -278,24 +302,30 @@
         @SysUISingleton
         public static class Factory {
             private final StatusBarPipelineFlags mStatusBarPipelineFlags;
-            private final Provider<WifiViewModel> mWifiViewModelProvider;
+            private final WifiViewModel mWifiViewModel;
             private final MobileContextProvider mMobileContextProvider;
+            private final MobileUiAdapter mMobileUiAdapter;
 
             @Inject
             public Factory(
                     StatusBarPipelineFlags statusBarPipelineFlags,
-                    Provider<WifiViewModel> wifiViewModelProvider,
-                    MobileContextProvider mobileContextProvider) {
+                    WifiViewModel wifiViewModel,
+                    MobileUiAdapter mobileUiAdapter,
+                    MobileContextProvider mobileContextProvider
+            ) {
                 mStatusBarPipelineFlags = statusBarPipelineFlags;
-                mWifiViewModelProvider = wifiViewModelProvider;
+                mWifiViewModel = wifiViewModel;
+                mMobileUiAdapter = mobileUiAdapter;
                 mMobileContextProvider = mobileContextProvider;
             }
 
-            public TintedIconManager create(ViewGroup group) {
+            public TintedIconManager create(ViewGroup group, StatusBarLocation location) {
                 return new TintedIconManager(
                         group,
+                        location,
                         mStatusBarPipelineFlags,
-                        mWifiViewModelProvider,
+                        mWifiViewModel,
+                        mMobileUiAdapter,
                         mMobileContextProvider);
             }
         }
@@ -306,9 +336,12 @@
      */
     class IconManager implements DemoModeCommandReceiver {
         protected final ViewGroup mGroup;
+        private final StatusBarLocation mLocation;
         private final StatusBarPipelineFlags mStatusBarPipelineFlags;
-        private final Provider<WifiViewModel> mWifiViewModelProvider;
+        private final WifiViewModel mWifiViewModel;
         private final MobileContextProvider mMobileContextProvider;
+        private final MobileIconsViewModel mMobileIconsViewModel;
+
         protected final Context mContext;
         protected final int mIconSize;
         // Whether or not these icons show up in dumpsys
@@ -324,16 +357,28 @@
 
         public IconManager(
                 ViewGroup group,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
-                MobileContextProvider mobileContextProvider) {
+                WifiViewModel wifiViewModel,
+                MobileUiAdapter mobileUiAdapter,
+                MobileContextProvider mobileContextProvider
+        ) {
             mGroup = group;
+            mLocation = location;
             mStatusBarPipelineFlags = statusBarPipelineFlags;
-            mWifiViewModelProvider = wifiViewModelProvider;
+            mWifiViewModel = wifiViewModel;
             mMobileContextProvider = mobileContextProvider;
             mContext = group.getContext();
             mIconSize = mContext.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.status_bar_icon_size);
+
+            if (statusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
+                // This starts the flow for the new pipeline, and will notify us of changes
+                mMobileIconsViewModel = mobileUiAdapter.createMobileIconsViewModel();
+                MobileIconsBinder.bind(mGroup, mMobileIconsViewModel);
+            } else {
+                mMobileIconsViewModel = null;
+            }
         }
 
         public boolean isDemoable() {
@@ -386,6 +431,9 @@
 
                 case TYPE_MOBILE:
                     return addMobileIcon(index, slot, holder.getMobileState());
+
+                case TYPE_MOBILE_NEW:
+                    return addNewMobileIcon(index, slot, holder.getTag());
             }
 
             return null;
@@ -402,7 +450,7 @@
 
         @VisibleForTesting
         protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) {
-            final BaseStatusBarWifiView view;
+            final BaseStatusBarFrameLayout view;
             if (mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
                 view = onCreateModernStatusBarWifiView(slot);
                 // When [ModernStatusBarWifiView] is created, it will automatically apply the
@@ -421,17 +469,47 @@
         }
 
         @VisibleForTesting
-        protected StatusBarMobileView addMobileIcon(int index, String slot, MobileIconState state) {
+        protected StatusIconDisplayable addMobileIcon(
+                int index,
+                String slot,
+                MobileIconState state
+        ) {
+            if (mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
+                throw new IllegalStateException("Attempting to add a mobile icon while the new "
+                        + "pipeline is enabled is not supported");
+            }
+
             // 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());
+            StatusBarMobileView mobileView = onCreateStatusBarMobileView(state.subId, slot);
+            mobileView.applyMobileState(state);
+            mGroup.addView(mobileView, index, onCreateLayoutParams());
 
             if (mIsInDemoMode) {
                 Context mobileContext = mMobileContextProvider
                         .getMobileContextForSub(state.subId, mContext);
                 mDemoStatusIcons.addMobileView(state, mobileContext);
             }
+            return mobileView;
+        }
+
+        protected StatusIconDisplayable addNewMobileIcon(
+                int index,
+                String slot,
+                int subId
+        ) {
+            if (!mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
+                throw new IllegalStateException("Attempting to add a mobile icon using the new"
+                        + "pipeline, but the enabled flag is false.");
+            }
+
+            BaseStatusBarFrameLayout view = onCreateModernStatusBarMobileView(slot, subId);
+            mGroup.addView(view, index, onCreateLayoutParams());
+
+            if (mIsInDemoMode) {
+                // TODO (b/249790009): demo mode should be handled at the data layer in the
+                //  new pipeline
+            }
+
             return view;
         }
 
@@ -446,7 +524,7 @@
 
         private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) {
             return ModernStatusBarWifiView.constructAndBind(
-                    mContext, slot, mWifiViewModelProvider.get());
+                    mContext, slot, mWifiViewModel, mLocation);
         }
 
         private StatusBarMobileView onCreateStatusBarMobileView(int subId, String slot) {
@@ -456,6 +534,15 @@
             return view;
         }
 
+        private ModernStatusBarMobileView onCreateModernStatusBarMobileView(
+                String slot, int subId) {
+            return ModernStatusBarMobileView
+                    .constructAndBind(
+                            mContext,
+                            slot,
+                            mMobileIconsViewModel.viewModelForSub(subId));
+        }
+
         protected LinearLayout.LayoutParams onCreateLayoutParams() {
             return new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize);
         }
@@ -511,6 +598,10 @@
                     return;
                 case TYPE_MOBILE:
                     onSetMobileIcon(viewIndex, holder.getMobileState());
+                    return;
+                case TYPE_MOBILE_NEW:
+                    // Nothing, the icon updates itself now
+                    return;
                 default:
                     break;
             }
@@ -534,9 +625,13 @@
         }
 
         public void onSetMobileIcon(int viewIndex, MobileIconState state) {
-            StatusBarMobileView view = (StatusBarMobileView) mGroup.getChildAt(viewIndex);
-            if (view != null) {
-                view.applyMobileState(state);
+            View view = mGroup.getChildAt(viewIndex);
+            if (view instanceof StatusBarMobileView) {
+                ((StatusBarMobileView) view).applyMobileState(state);
+            } else {
+                // ModernStatusBarMobileView automatically updates via the ViewModel
+                throw new IllegalStateException("Cannot update ModernStatusBarMobileView outside of"
+                        + "the new pipeline");
             }
 
             if (mIsInDemoMode) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index 7c31366..e106b9e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 import com.android.systemui.tuner.TunerService;
@@ -66,8 +67,8 @@
     private final StatusBarIconList mStatusBarIconList;
     private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
     private final ArraySet<String> mIconHideList = new ArraySet<>();
-
-    private Context mContext;
+    private final StatusBarPipelineFlags mStatusBarPipelineFlags;
+    private final Context mContext;
 
     /** */
     @Inject
@@ -78,9 +79,12 @@
             ConfigurationController configurationController,
             TunerService tunerService,
             DumpManager dumpManager,
-            StatusBarIconList statusBarIconList) {
+            StatusBarIconList statusBarIconList,
+            StatusBarPipelineFlags statusBarPipelineFlags
+    ) {
         mStatusBarIconList = statusBarIconList;
         mContext = context;
+        mStatusBarPipelineFlags = statusBarPipelineFlags;
 
         configurationController.addCallback(this);
         commandQueue.addCallback(this);
@@ -220,6 +224,11 @@
      */
     @Override
     public void setMobileIcons(String slot, List<MobileIconState> iconStates) {
+        if (mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
+            Log.d(TAG, "ignoring old pipeline callbacks, because the new "
+                    + "pipeline frontend is enabled");
+            return;
+        }
         Slot mobileSlot = mStatusBarIconList.getSlot(slot);
 
         // Reverse the sort order to show icons with left to right([Slot1][Slot2]..).
@@ -227,7 +236,6 @@
         Collections.reverse(iconStates);
 
         for (MobileIconState state : iconStates) {
-
             StatusBarIconHolder holder = mobileSlot.getHolderForTag(state.subId);
             if (holder == null) {
                 holder = StatusBarIconHolder.fromMobileIconState(state);
@@ -239,6 +247,28 @@
         }
     }
 
+    @Override
+    public void setNewMobileIconSubIds(List<Integer> subIds) {
+        if (!mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
+            Log.d(TAG, "ignoring new pipeline callback, "
+                    + "since the frontend is disabled");
+            return;
+        }
+        Slot mobileSlot = mStatusBarIconList.getSlot("mobile");
+
+        Collections.reverse(subIds);
+
+        for (Integer subId : subIds) {
+            StatusBarIconHolder holder = mobileSlot.getHolderForTag(subId);
+            if (holder == null) {
+                holder = StatusBarIconHolder.fromSubIdForModernMobileIcon(subId);
+                setIcon("mobile", holder);
+            } else {
+                // Don't have to do anything in the new world
+            }
+        }
+    }
+
     /**
      * Accept a list of CallIndicatorIconStates, and show the call strength icons.
      * @param slot statusbar slot for the call strength icons
@@ -384,8 +414,6 @@
         }
     }
 
-
-
     private void handleSet(String slotName, StatusBarIconHolder holder) {
         int viewIndex = mStatusBarIconList.getViewIndex(slotName, holder.getTag());
         mIconGroups.forEach(l -> l.onSetIconHolder(viewIndex, holder));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
index af342dd..68a203e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconHolder.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.graphics.drawable.Icon;
@@ -25,6 +26,10 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * Wraps {@link com.android.internal.statusbar.StatusBarIcon} so we can still have a uniform list
@@ -33,15 +38,35 @@
     public static final int TYPE_ICON = 0;
     public static final int TYPE_WIFI = 1;
     public static final int TYPE_MOBILE = 2;
+    /**
+     * TODO (b/249790733): address this once the new pipeline is in place
+     * This type exists so that the new pipeline (see {@link MobileIconViewModel}) can be used
+     * to inform the old view system about changes to the data set (the list of mobile icons). The
+     * design of the new pipeline should allow for removal of this icon holder type, and obsolete
+     * the need for this entire class.
+     *
+     * @deprecated This field only exists so the new status bar pipeline can interface with the
+     * view holder system.
+     */
+    @Deprecated
+    public static final int TYPE_MOBILE_NEW = 3;
+
+    @IntDef({
+            TYPE_ICON,
+            TYPE_WIFI,
+            TYPE_MOBILE,
+            TYPE_MOBILE_NEW
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface IconType {}
 
     private StatusBarIcon mIcon;
     private WifiIconState mWifiState;
     private MobileIconState mMobileState;
-    private int mType = TYPE_ICON;
+    private @IconType int mType = TYPE_ICON;
     private int mTag = 0;
 
     private StatusBarIconHolder() {
-
     }
 
     public static StatusBarIconHolder fromIcon(StatusBarIcon icon) {
@@ -80,6 +105,18 @@
     }
 
     /**
+     * ONLY for use with the new connectivity pipeline, where we only need a subscriptionID to
+     * determine icon ordering and building the correct view model
+     */
+    public static StatusBarIconHolder fromSubIdForModernMobileIcon(int subId) {
+        StatusBarIconHolder holder = new StatusBarIconHolder();
+        holder.mType = TYPE_MOBILE_NEW;
+        holder.mTag = subId;
+
+        return holder;
+    }
+
+    /**
      * Creates a new StatusBarIconHolder from a CallIndicatorIconState.
      */
     public static StatusBarIconHolder fromCallIndicatorState(
@@ -95,7 +132,7 @@
         return holder;
     }
 
-    public int getType() {
+    public @IconType int getType() {
         return mType;
     }
 
@@ -134,8 +171,12 @@
                 return mWifiState.visible;
             case TYPE_MOBILE:
                 return mMobileState.visible;
+            case TYPE_MOBILE_NEW:
+                //TODO (b/249790733), the new pipeline can control visibility via the ViewModel
+                return true;
 
-            default: return true;
+            default:
+                return true;
         }
     }
 
@@ -156,6 +197,10 @@
             case TYPE_MOBILE:
                 mMobileState.visible = visible;
                 break;
+
+            case TYPE_MOBILE_NEW:
+                //TODO (b/249790733), the new pipeline can control visibility via the ViewModel
+                break;
         }
     }
 
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 e61794b..6e1cf13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,12 +31,15 @@
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.view.WindowManagerGlobal;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -119,6 +122,7 @@
     private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
 
     private static String TAG = "StatusBarKeyguardViewManager";
+    private static final boolean DEBUG = false;
 
     protected final Context mContext;
     private final ConfigurationController mConfigurationController;
@@ -184,8 +188,25 @@
             if (mAlternateAuthInterceptor != null) {
                 mAlternateAuthInterceptor.onBouncerVisibilityChanged();
             }
+
+            /* Register predictive back callback when keyguard becomes visible, and unregister
+            when it's hidden. */
+            if (isVisible) {
+                registerBackCallback();
+            } else {
+                unregisterBackCallback();
+            }
         }
     };
+
+    private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+        if (DEBUG) {
+            Log.d(TAG, "onBackInvokedCallback() called, invoking onBackPressed()");
+        }
+        onBackPressed(false /* unused */);
+    };
+    private boolean mIsBackCallbackRegistered = false;
+
     private final DockManager.DockEventListener mDockEventListener =
             new DockManager.DockEventListener() {
                 @Override
@@ -378,6 +399,46 @@
         }
     }
 
+    /** Register a callback, to be invoked by the Predictive Back system. */
+    private void registerBackCallback() {
+        if (!mIsBackCallbackRegistered) {
+            ViewRootImpl viewRoot = getViewRootImpl();
+            if (viewRoot != null) {
+                viewRoot.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                        OnBackInvokedDispatcher.PRIORITY_OVERLAY, mOnBackInvokedCallback);
+                mIsBackCallbackRegistered = true;
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "view root was null, could not register back callback");
+                }
+            }
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "prevented registering back callback twice");
+            }
+        }
+    }
+
+    /** Unregister the callback formerly registered with the Predictive Back system. */
+    private void unregisterBackCallback() {
+        if (mIsBackCallbackRegistered) {
+            ViewRootImpl viewRoot = getViewRootImpl();
+            if (viewRoot != null) {
+                viewRoot.getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(
+                        mOnBackInvokedCallback);
+                mIsBackCallbackRegistered = false;
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "view root was null, could not unregister back callback");
+                }
+            }
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "prevented unregistering back callback twice");
+            }
+        }
+    }
+
     @Override
     public void onDensityOrFontScaleChanged() {
         hideBouncer(true /* destroyView */);
@@ -405,8 +466,9 @@
         } else if (mNotificationPanelViewController.isUnlockHintRunning()) {
             if (mBouncer != null) {
                 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+            } else {
+                mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
             }
-            mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
         } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
             // Don't expand to the bouncer. Instead transition back to the lock screen (see
             // CentralSurfaces#showBouncerOrLockScreenIfKeyguard)
@@ -414,8 +476,9 @@
         } else if (bouncerNeedsScrimming()) {
             if (mBouncer != null) {
                 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
+            } else {
+                mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
             }
-            mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
         } else if (mShowing && !hideBouncerOverDream) {
             if (!isWakeAndUnlocking()
                     && !(mBiometricUnlockController.getMode() == MODE_DISMISS_BOUNCER)
@@ -423,8 +486,9 @@
                     && !isUnlockCollapsing()) {
                 if (mBouncer != null) {
                     mBouncer.setExpansion(fraction);
+                } else {
+                    mBouncerInteractor.setExpansion(fraction);
                 }
-                mBouncerInteractor.setExpansion(fraction);
             }
             if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking
                     && !mKeyguardStateController.canDismissLockScreen()
@@ -432,16 +496,18 @@
                     && !bouncerIsAnimatingAway()) {
                 if (mBouncer != null) {
                     mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
+                } else {
+                    mBouncerInteractor.show(/* isScrimmed= */false);
                 }
-                mBouncerInteractor.show(/* isScrimmed= */false);
             }
         } else if (!mShowing && isBouncerInTransit()) {
             // Keyguard is not visible anymore, but expansion animation was still running.
             // We need to hide the bouncer, otherwise it will be stuck in transit.
             if (mBouncer != null) {
                 mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
+            } else {
+                mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
             }
-            mBouncerInteractor.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
         } else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) {
             // Panel expanded while pulsing but didn't translate the bouncer (because we are
             // unlocked.) Let's simply wake-up to dismiss the lock screen.
@@ -487,8 +553,9 @@
             mCentralSurfaces.hideKeyguard();
             if (mBouncer != null) {
                 mBouncer.show(true /* resetSecuritySelection */);
+            } else {
+                mBouncerInteractor.show(true);
             }
-            mBouncerInteractor.show(true);
         } else {
             mCentralSurfaces.showKeyguard();
             if (hideBouncerWhenShowing) {
@@ -529,8 +596,9 @@
     void hideBouncer(boolean destroyView) {
         if (mBouncer != null) {
             mBouncer.hide(destroyView);
+        } else {
+            mBouncerInteractor.hide();
         }
-        mBouncerInteractor.hide();
         if (mShowing) {
             // If we were showing the bouncer and then aborting, we need to also clear out any
             // potential actions unless we actually unlocked.
@@ -551,8 +619,9 @@
         if (mShowing && !isBouncerShowing()) {
             if (mBouncer != null) {
                 mBouncer.show(false /* resetSecuritySelection */, scrimmed);
+            } else {
+                mBouncerInteractor.show(scrimmed);
             }
-            mBouncerInteractor.show(scrimmed);
         }
         updateStates();
     }
@@ -588,9 +657,10 @@
                         if (mBouncer != null) {
                             mBouncer.setDismissAction(mAfterKeyguardGoneAction,
                                     mKeyguardGoneCancelAction);
+                        } else {
+                            mBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
+                                    mKeyguardGoneCancelAction);
                         }
-                        mBouncerInteractor.setDismissAction(mAfterKeyguardGoneAction,
-                                mKeyguardGoneCancelAction);
                         mAfterKeyguardGoneAction = null;
                         mKeyguardGoneCancelAction = null;
                     }
@@ -603,17 +673,21 @@
                 if (afterKeyguardGone) {
                     // we'll handle the dismiss action after keyguard is gone, so just show the
                     // bouncer
-                    mBouncerInteractor.show(/* isScrimmed= */true);
-                    if (mBouncer != null) mBouncer.show(false /* resetSecuritySelection */);
+                    if (mBouncer != null) {
+                        mBouncer.show(false /* resetSecuritySelection */);
+                    } else {
+                        mBouncerInteractor.show(/* isScrimmed= */true);
+                    }
                 } else {
                     // after authentication success, run dismiss action with the option to defer
                     // hiding the keyguard based on the return value of the OnDismissAction
-                    mBouncerInteractor.setDismissAction(
-                            mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
-                    mBouncerInteractor.show(/* isScrimmed= */true);
                     if (mBouncer != null) {
                         mBouncer.showWithDismissAction(mAfterKeyguardGoneAction,
                                 mKeyguardGoneCancelAction);
+                    } else {
+                        mBouncerInteractor.setDismissAction(
+                                mAfterKeyguardGoneAction, mKeyguardGoneCancelAction);
+                        mBouncerInteractor.show(/* isScrimmed= */true);
                     }
                     // bouncer will handle the dismiss action, so we no longer need to track it here
                     mAfterKeyguardGoneAction = null;
@@ -717,8 +791,9 @@
     public void onFinishedGoingToSleep() {
         if (mBouncer != null) {
             mBouncer.onScreenTurnedOff();
+        } else {
+            mBouncerInteractor.onScreenTurnedOff();
         }
-        mBouncerInteractor.onScreenTurnedOff();
     }
 
     @Override
@@ -730,7 +805,9 @@
     private void setDozing(boolean dozing) {
         if (mDozing != dozing) {
             mDozing = dozing;
-            reset(true /* hideBouncerWhenShowing */);
+            if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
+                reset(dozing /* hideBouncerWhenShowing */);
+            }
             updateStates();
 
             if (!dozing) {
@@ -828,8 +905,9 @@
         if (bouncerIsShowing()) {
             if (mBouncer != null) {
                 mBouncer.startPreHideAnimation(finishRunnable);
+            } else {
+                mBouncerInteractor.startDisappearAnimation(finishRunnable);
             }
-            mBouncerInteractor.startDisappearAnimation(finishRunnable);
             mCentralSurfaces.onBouncerPreHideAnimation();
 
             // We update the state (which will show the keyguard) only if an animation will run on
@@ -1008,25 +1086,47 @@
     }
 
     /**
-     * Notifies this manager that the back button has been pressed.
+     * Returns whether a back invocation can be handled, which depends on whether the keyguard
+     * is currently showing (which itself is derived from multiple states).
      *
-     * @param hideImmediately Hide bouncer when {@code true}, keep it around otherwise.
-     *                        Non-scrimmed bouncers have a special animation tied to the expansion
-     *                        of the notification panel.
-     * @return whether the back press has been handled
+     * @return whether a back press can be handled right now.
      */
-    public boolean onBackPressed(boolean hideImmediately) {
-        if (bouncerIsShowing()) {
-            mCentralSurfaces.endAffordanceLaunch();
-            // The second condition is for SIM card locked bouncer
-            if (bouncerIsScrimmed()
-                    && !needsFullscreenBouncer()) {
-                hideBouncer(false);
-                updateStates();
+    public boolean canHandleBackPressed() {
+        return mBouncer.isShowing();
+    }
+
+    /**
+     * Notifies this manager that the back button has been pressed.
+     */
+    // TODO(b/244635782): This "accept boolean and ignore it, and always return false" was done
+    //                    to make it possible to check this in *and* allow merging to master,
+    //                    where ArcStatusBarKeyguardViewManager inherits this class, and its
+    //                    build will break if we change this interface.
+    //                    So, overall, while this function refactors the behavior of onBackPressed,
+    //                    (it now handles the back press, and no longer returns *whether* it did so)
+    //                    its interface is not changing right now (but will, in a follow-up CL).
+    public boolean onBackPressed(boolean ignored) {
+        if (!canHandleBackPressed()) {
+            return false;
+        }
+
+        mCentralSurfaces.endAffordanceLaunch();
+        // The second condition is for SIM card locked bouncer
+        if (bouncerIsScrimmed() && needsFullscreenBouncer()) {
+            hideBouncer(false);
+            updateStates();
+        } else {
+            /* Non-scrimmed bouncers have a special animation tied to the expansion
+             * of the notification panel. We decide whether to kick this animation off
+             * by computing the hideImmediately boolean.
+             */
+            boolean hideImmediately = mCentralSurfaces.shouldKeyguardHideImmediately();
+            reset(hideImmediately);
+            if (hideImmediately) {
+                mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
             } else {
-                reset(hideImmediately);
+                mNotificationPanelViewController.expandWithoutQs();
             }
-            return true;
         }
         return false;
     }
@@ -1100,13 +1200,15 @@
             if (bouncerDismissible || !showing || remoteInputActive) {
                 if (mBouncer != null) {
                     mBouncer.setBackButtonEnabled(true);
+                } else {
+                    mBouncerInteractor.setBackButtonEnabled(true);
                 }
-                mBouncerInteractor.setBackButtonEnabled(true);
             } else {
                 if (mBouncer != null) {
                     mBouncer.setBackButtonEnabled(false);
+                } else {
+                    mBouncerInteractor.setBackButtonEnabled(false);
                 }
-                mBouncerInteractor.setBackButtonEnabled(false);
             }
         }
 
@@ -1124,8 +1226,8 @@
         if (occluded != mLastOccluded || mFirstUpdate) {
             mKeyguardStateController.notifyKeyguardState(showing, occluded);
         }
-        if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
-            mKeyguardUpdateManager.onKeyguardVisibilityChanged(showing && !occluded);
+        if (occluded != mLastOccluded || mShowing != showing || mFirstUpdate) {
+            mKeyguardUpdateManager.setKeyguardShowing(showing, occluded);
         }
         if (bouncerIsOrWillBeShowing != mLastBouncerIsOrWillBeShowing || mFirstUpdate
                 || bouncerShowing != mLastBouncerShowing) {
@@ -1272,8 +1374,9 @@
     public void notifyKeyguardAuthenticated(boolean strongAuth) {
         if (mBouncer != null) {
             mBouncer.notifyKeyguardAuthenticated(strongAuth);
+        } else {
+            mBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
         }
-        mBouncerInteractor.notifyKeyguardAuthenticated(strongAuth);
 
         if (mAlternateAuthInterceptor != null && isShowingAlternateAuthOrAnimating()) {
             resetAlternateAuth(false);
@@ -1290,14 +1393,23 @@
         } else {
             if (mBouncer != null) {
                 mBouncer.showMessage(message, colorState);
+            } else {
+                mBouncerInteractor.showMessage(message, colorState);
             }
-            mBouncerInteractor.showMessage(message, colorState);
         }
     }
 
     @Override
     public ViewRootImpl getViewRootImpl() {
-        return mNotificationShadeWindowController.getNotificationShadeView().getViewRootImpl();
+        ViewGroup viewGroup = mNotificationShadeWindowController.getNotificationShadeView();
+        if (viewGroup != null) {
+            return viewGroup.getViewRootImpl();
+        } else {
+            if (DEBUG) {
+                Log.d(TAG, "ViewGroup was null, cannot get ViewRootImpl");
+            }
+            return null;
+        }
     }
 
     public void launchPendingWakeupAction() {
@@ -1338,8 +1450,9 @@
     public void updateResources() {
         if (mBouncer != null) {
             mBouncer.updateResources();
+        } else {
+            mBouncerInteractor.updateResources();
         }
-        mBouncerInteractor.updateResources();
     }
 
     public void dump(PrintWriter pw) {
@@ -1424,9 +1537,9 @@
     public void updateKeyguardPosition(float x) {
         if (mBouncer != null) {
             mBouncer.updateKeyguardPosition(x);
+        } else {
+            mBouncerInteractor.setKeyguardPosition(x);
         }
-
-        mBouncerInteractor.setKeyguardPosition(x);
     }
 
     private static class DismissWithActionRequest {
@@ -1468,9 +1581,9 @@
     public boolean isBouncerInTransit() {
         if (mBouncer != null) {
             return mBouncer.inTransit();
+        } else {
+            return mBouncerInteractor.isInTransit();
         }
-
-        return mBouncerInteractor.isInTransit();
     }
 
     /**
@@ -1479,9 +1592,9 @@
     public boolean bouncerIsShowing() {
         if (mBouncer != null) {
             return mBouncer.isShowing();
+        } else {
+            return mBouncerInteractor.isFullyShowing();
         }
-
-        return mBouncerInteractor.isFullyShowing();
     }
 
     /**
@@ -1490,9 +1603,9 @@
     public boolean bouncerIsScrimmed() {
         if (mBouncer != null) {
             return mBouncer.isScrimmed();
+        } else {
+            return mBouncerInteractor.isScrimmed();
         }
-
-        return mBouncerInteractor.isScrimmed();
     }
 
     /**
@@ -1501,9 +1614,10 @@
     public boolean bouncerIsAnimatingAway() {
         if (mBouncer != null) {
             return mBouncer.isAnimatingAway();
+        } else {
+            return mBouncerInteractor.isAnimatingAway();
         }
 
-        return mBouncerInteractor.isAnimatingAway();
     }
 
     /**
@@ -1512,9 +1626,9 @@
     public boolean bouncerWillDismissWithAction() {
         if (mBouncer != null) {
             return mBouncer.willDismissWithAction();
+        } else {
+            return mBouncerInteractor.willDismissWithAction();
         }
-
-        return mBouncerInteractor.willDismissWithAction();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
index 44c0496..5ace226 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.systemui.statusbar.phone
 
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+/** An enumeration of the different locations that host a status bar. */
+enum class StatusBarLocation {
+    /** Home screen or in-app. */
+    HOME,
+    /** Keyguard (aka lockscreen). */
+    KEYGUARD,
+    /** Quick settings (inside the shade). */
+    QS,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
index d464acb..26c1767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java
@@ -337,7 +337,7 @@
             // without cutting off the child view.
             translationX -= getViewTotalWidth(child);
             childState.visibleState = STATE_ICON;
-            childState.xTranslation = translationX;
+            childState.setXTranslation(translationX);
             mLayoutStates.add(0, childState);
 
             // Shift translationX over by mIconSpacing for the next view.
@@ -354,13 +354,13 @@
         for (int i = totalVisible - 1; i >= 0; i--) {
             StatusIconState state = mLayoutStates.get(i);
             // Allow room for underflow if we found we need it in onMeasure
-            if (mNeedsUnderflow && (state.xTranslation < (contentStart + mUnderflowWidth))||
-                    (mShouldRestrictIcons && visible >= maxVisible)) {
+            if (mNeedsUnderflow && (state.getXTranslation() < (contentStart + mUnderflowWidth))
+                    || (mShouldRestrictIcons && (visible >= maxVisible))) {
                 firstUnderflowIndex = i;
                 break;
             }
             mUnderflowStart = (int) Math.max(
-                    contentStart, state.xTranslation - mUnderflowWidth - mIconSpacing);
+                    contentStart, state.getXTranslation() - mUnderflowWidth - mIconSpacing);
             visible++;
         }
 
@@ -371,7 +371,7 @@
             for (int i = firstUnderflowIndex; i >= 0; i--) {
                 StatusIconState state = mLayoutStates.get(i);
                 if (totalDots < MAX_DOTS) {
-                    state.xTranslation = dotOffset;
+                    state.setXTranslation(dotOffset);
                     state.visibleState = STATE_DOT;
                     dotOffset -= dotWidth;
                     totalDots++;
@@ -386,7 +386,7 @@
             for (int i = 0; i < childCount; i++) {
                 View child = getChildAt(i);
                 StatusIconState state = getViewStateFromChild(child);
-                state.xTranslation = width - state.xTranslation - child.getWidth();
+                state.setXTranslation(width - state.getXTranslation() - child.getWidth());
             }
         }
     }
@@ -410,7 +410,7 @@
             }
 
             vs.initFrom(child);
-            vs.alpha = 1.0f;
+            vs.setAlpha(1.0f);
             vs.hidden = false;
         }
     }
@@ -442,7 +442,7 @@
                 parentWidth = ((View) view.getParent()).getWidth();
             }
 
-            float currentDistanceToEnd = parentWidth - xTranslation;
+            float currentDistanceToEnd = parentWidth - getXTranslation();
 
             if (!(view instanceof StatusIconDisplayable)) {
                 return;
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 ce04fb5..e1215ee 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
@@ -68,6 +68,7 @@
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent.Startable;
@@ -250,7 +251,8 @@
             mStatusBar.restoreHierarchyState(
                     savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
         }
-        mDarkIconManager = mDarkIconManagerFactory.create(view.findViewById(R.id.statusIcons));
+        mDarkIconManager = mDarkIconManagerFactory.create(
+                view.findViewById(R.id.statusIcons), StatusBarLocation.HOME);
         mDarkIconManager.setShouldLog(true);
         updateBlockedIcons();
         mStatusBarIconController.addIconGroup(mDarkIconManager);
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 9a7c3fa..06d5542 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
@@ -16,6 +16,10 @@
 
 package com.android.systemui.statusbar.pipeline.dagger
 
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepositoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepositoryImpl
 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
@@ -30,4 +34,12 @@
 
     @Binds
     abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
+
+    @Binds
+    abstract fun mobileSubscriptionRepository(
+        impl: MobileSubscriptionRepositoryImpl
+    ): MobileSubscriptionRepository
+
+    @Binds
+    abstract fun userSetupRepository(impl: UserSetupRepositoryImpl): UserSetupRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt
new file mode 100644
index 0000000..46ccf32c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/model/MobileSubscriptionModel.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.data.model
+
+import android.annotation.IntRange
+import android.telephony.Annotation.DataActivityType
+import android.telephony.CellSignalStrength
+import android.telephony.TelephonyCallback.CarrierNetworkListener
+import android.telephony.TelephonyCallback.DataActivityListener
+import android.telephony.TelephonyCallback.DataConnectionStateListener
+import android.telephony.TelephonyCallback.DisplayInfoListener
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyCallback.SignalStrengthsListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
+
+/**
+ * Data class containing all of the relevant information for a particular line of service, known as
+ * a Subscription in the telephony world. These models are the result of a single telephony listener
+ * which has many callbacks which each modify some particular field on this object.
+ *
+ * The design goal here is to de-normalize fields from the system into our model fields below. So
+ * any new field that needs to be tracked should be copied into this data class rather than
+ * threading complex system objects through the pipeline.
+ */
+data class MobileSubscriptionModel(
+    /** From [ServiceStateListener.onServiceStateChanged] */
+    val isEmergencyOnly: Boolean = false,
+
+    /** From [SignalStrengthsListener.onSignalStrengthsChanged] */
+    val isGsm: Boolean = false,
+    @IntRange(from = 0, to = 4)
+    val cdmaLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+    @IntRange(from = 0, to = 4)
+    val primaryLevel: Int = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN,
+
+    /** Comes directly from [DataConnectionStateListener.onDataConnectionStateChanged] */
+    val dataConnectionState: Int? = null,
+
+    /** From [DataActivityListener.onDataActivity]. See [TelephonyManager] for the values */
+    @DataActivityType val dataActivityDirection: Int? = null,
+
+    /** From [CarrierNetworkListener.onCarrierNetworkChange] */
+    val carrierNetworkChangeActive: Boolean? = null,
+
+    /** From [DisplayInfoListener.onDisplayInfoChanged] */
+    val displayInfo: TelephonyDisplayInfo? = null
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepository.kt
new file mode 100644
index 0000000..36de2a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepository.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.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.CellSignalStrength
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyCallback.CarrierNetworkListener
+import android.telephony.TelephonyCallback.DataActivityListener
+import android.telephony.TelephonyCallback.DataConnectionStateListener
+import android.telephony.TelephonyCallback.DisplayInfoListener
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyCallback.SignalStrengthsListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/**
+ * Repo for monitoring the complete active subscription info list, to be consumed and filtered based
+ * on various policy
+ */
+interface MobileSubscriptionRepository {
+    /** Observable list of current mobile subscriptions */
+    val subscriptionsFlow: Flow<List<SubscriptionInfo>>
+
+    /** Observable for the subscriptionId of the current mobile data connection */
+    val activeMobileDataSubscriptionId: Flow<Int>
+
+    /** Get or create an observable for the given subscription ID */
+    fun getFlowForSubId(subId: Int): Flow<MobileSubscriptionModel>
+}
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class MobileSubscriptionRepositoryImpl
+@Inject
+constructor(
+    private val subscriptionManager: SubscriptionManager,
+    private val telephonyManager: TelephonyManager,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    @Application private val scope: CoroutineScope,
+) : MobileSubscriptionRepository {
+    private val subIdFlowCache: MutableMap<Int, StateFlow<MobileSubscriptionModel>> = mutableMapOf()
+
+    /**
+     * State flow that emits the set of mobile data subscriptions, each represented by its own
+     * [SubscriptionInfo]. We probably only need the [SubscriptionInfo.getSubscriptionId] of each
+     * info object, but for now we keep track of the infos themselves.
+     */
+    override val subscriptionsFlow: StateFlow<List<SubscriptionInfo>> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : SubscriptionManager.OnSubscriptionsChangedListener() {
+                        override fun onSubscriptionsChanged() {
+                            trySend(Unit)
+                        }
+                    }
+
+                subscriptionManager.addOnSubscriptionsChangedListener(
+                    bgDispatcher.asExecutor(),
+                    callback,
+                )
+
+                awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
+            }
+            .mapLatest { fetchSubscriptionsList() }
+            .stateIn(scope, started = SharingStarted.WhileSubscribed(), listOf())
+
+    /** StateFlow that keeps track of the current active mobile data subscription */
+    override val activeMobileDataSubscriptionId: StateFlow<Int> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : TelephonyCallback(), ActiveDataSubscriptionIdListener {
+                        override fun onActiveDataSubscriptionIdChanged(subId: Int) {
+                            trySend(subId)
+                        }
+                    }
+
+                telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+                awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+            }
+            .stateIn(
+                scope,
+                started = SharingStarted.WhileSubscribed(),
+                SubscriptionManager.INVALID_SUBSCRIPTION_ID
+            )
+
+    /**
+     * Each mobile subscription needs its own flow, which comes from registering listeners on the
+     * system. Use this method to create those flows and cache them for reuse
+     */
+    override fun getFlowForSubId(subId: Int): StateFlow<MobileSubscriptionModel> {
+        return subIdFlowCache[subId]
+            ?: createFlowForSubId(subId).also { subIdFlowCache[subId] = it }
+    }
+
+    @VisibleForTesting fun getSubIdFlowCache() = subIdFlowCache
+
+    private fun createFlowForSubId(subId: Int): StateFlow<MobileSubscriptionModel> = run {
+        var state = MobileSubscriptionModel()
+        conflatedCallbackFlow {
+                val phony = telephonyManager.createForSubscriptionId(subId)
+                // TODO (b/240569788): log all of these into the connectivity logger
+                val callback =
+                    object :
+                        TelephonyCallback(),
+                        ServiceStateListener,
+                        SignalStrengthsListener,
+                        DataConnectionStateListener,
+                        DataActivityListener,
+                        CarrierNetworkListener,
+                        DisplayInfoListener {
+                        override fun onServiceStateChanged(serviceState: ServiceState) {
+                            state = state.copy(isEmergencyOnly = serviceState.isEmergencyOnly)
+                            trySend(state)
+                        }
+                        override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
+                            val cdmaLevel =
+                                signalStrength
+                                    .getCellSignalStrengths(CellSignalStrengthCdma::class.java)
+                                    .let { strengths ->
+                                        if (!strengths.isEmpty()) {
+                                            strengths[0].level
+                                        } else {
+                                            CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+                                        }
+                                    }
+
+                            val primaryLevel = signalStrength.level
+
+                            state =
+                                state.copy(
+                                    cdmaLevel = cdmaLevel,
+                                    primaryLevel = primaryLevel,
+                                    isGsm = signalStrength.isGsm,
+                                )
+                            trySend(state)
+                        }
+                        override fun onDataConnectionStateChanged(
+                            dataState: Int,
+                            networkType: Int
+                        ) {
+                            state = state.copy(dataConnectionState = dataState)
+                            trySend(state)
+                        }
+                        override fun onDataActivity(direction: Int) {
+                            state = state.copy(dataActivityDirection = direction)
+                            trySend(state)
+                        }
+                        override fun onCarrierNetworkChange(active: Boolean) {
+                            state = state.copy(carrierNetworkChangeActive = active)
+                            trySend(state)
+                        }
+                        override fun onDisplayInfoChanged(
+                            telephonyDisplayInfo: TelephonyDisplayInfo
+                        ) {
+                            state = state.copy(displayInfo = telephonyDisplayInfo)
+                            trySend(state)
+                        }
+                    }
+                phony.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+                awaitClose {
+                    phony.unregisterTelephonyCallback(callback)
+                    // Release the cached flow
+                    subIdFlowCache.remove(subId)
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), state)
+    }
+
+    private suspend fun fetchSubscriptionsList(): List<SubscriptionInfo> =
+        withContext(bgDispatcher) { subscriptionManager.completeActiveSubscriptionInfoList }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
new file mode 100644
index 0000000..77de849
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.data.repository
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.withContext
+
+/**
+ * Repository to observe the state of [DeviceProvisionedController.isUserSetup]. This information
+ * can change some policy related to display
+ */
+interface UserSetupRepository {
+    /** Observable tracking [DeviceProvisionedController.isUserSetup] */
+    val isUserSetupFlow: Flow<Boolean>
+}
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class UserSetupRepositoryImpl
+@Inject
+constructor(
+    private val deviceProvisionedController: DeviceProvisionedController,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    @Application scope: CoroutineScope,
+) : UserSetupRepository {
+    /** State flow that tracks [DeviceProvisionedController.isUserSetup] */
+    override val isUserSetupFlow: StateFlow<Boolean> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : DeviceProvisionedController.DeviceProvisionedListener {
+                        override fun onUserSetupChanged() {
+                            trySend(Unit)
+                        }
+                    }
+
+                deviceProvisionedController.addCallback(callback)
+
+                awaitClose { deviceProvisionedController.removeCallback(callback) }
+            }
+            .onStart { emit(Unit) }
+            .mapLatest { fetchUserSetupState() }
+            .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    private suspend fun fetchUserSetupState(): Boolean =
+        withContext(bgDispatcher) { deviceProvisionedController.isCurrentUserSetup }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
new file mode 100644
index 0000000..40fe0f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.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.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.telephony.CarrierConfigManager
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.systemui.util.CarrierConfigTracker
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+interface MobileIconInteractor {
+    /** Identifier for RAT type indicator */
+    val iconGroup: Flow<SignalIcon.MobileIconGroup>
+    /** True if this line of service is emergency-only */
+    val isEmergencyOnly: Flow<Boolean>
+    /** Int describing the connection strength. 0-4 OR 1-5. See [numberOfLevels] */
+    val level: Flow<Int>
+    /** Based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL], either 4 or 5 */
+    val numberOfLevels: Flow<Int>
+    /** True when we want to draw an icon that makes room for the exclamation mark */
+    val cutOut: Flow<Boolean>
+}
+
+/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
+class MobileIconInteractorImpl(
+    mobileStatusInfo: Flow<MobileSubscriptionModel>,
+) : MobileIconInteractor {
+    override val iconGroup: Flow<SignalIcon.MobileIconGroup> = flowOf(TelephonyIcons.THREE_G)
+    override val isEmergencyOnly: Flow<Boolean> = mobileStatusInfo.map { it.isEmergencyOnly }
+
+    override val level: Flow<Int> =
+        mobileStatusInfo.map { mobileModel ->
+            // TODO: incorporate [MobileMappings.Config.alwaysShowCdmaRssi]
+            if (mobileModel.isGsm) {
+                mobileModel.primaryLevel
+            } else {
+                mobileModel.cdmaLevel
+            }
+        }
+
+    /**
+     * This will become variable based on [CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL]
+     * once it's wired up inside of [CarrierConfigTracker]
+     */
+    override val numberOfLevels: Flow<Int> = flowOf(4)
+
+    /** Whether or not to draw the mobile triangle as "cut out", i.e., with the exclamation mark */
+    // TODO: find a better name for this?
+    override val cutOut: Flow<Boolean> = flowOf(false)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
new file mode 100644
index 0000000..8e67e19
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.domain.interactor
+
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileSubscriptionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
+import com.android.systemui.util.CarrierConfigTracker
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+
+/**
+ * Business layer logic for mobile subscription icons
+ *
+ * Mobile indicators represent the UI for the (potentially filtered) list of [SubscriptionInfo]s
+ * that the system knows about. They obey policy that depends on OEM, carrier, and locale configs
+ */
+@SysUISingleton
+class MobileIconsInteractor
+@Inject
+constructor(
+    private val mobileSubscriptionRepo: MobileSubscriptionRepository,
+    private val carrierConfigTracker: CarrierConfigTracker,
+    userSetupRepo: UserSetupRepository,
+) {
+    private val activeMobileDataSubscriptionId =
+        mobileSubscriptionRepo.activeMobileDataSubscriptionId
+
+    private val unfilteredSubscriptions: Flow<List<SubscriptionInfo>> =
+        mobileSubscriptionRepo.subscriptionsFlow
+
+    /**
+     * Generally, SystemUI wants to show iconography for each subscription that is listed by
+     * [SubscriptionManager]. However, in the case of opportunistic subscriptions, we want to only
+     * show a single representation of the pair of subscriptions. The docs define opportunistic as:
+     *
+     * "A subscription is opportunistic (if) the network it connects to has limited coverage"
+     * https://developer.android.com/reference/android/telephony/SubscriptionManager#setOpportunistic(boolean,%20int)
+     *
+     * In the case of opportunistic networks (typically CBRS), we will filter out one of the
+     * subscriptions based on
+     * [CarrierConfigManager.KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN],
+     * and by checking which subscription is opportunistic, or which one is active.
+     */
+    val filteredSubscriptions: Flow<List<SubscriptionInfo>> =
+        combine(unfilteredSubscriptions, activeMobileDataSubscriptionId) { unfilteredSubs, activeId
+            ->
+            // Based on the old logic,
+            if (unfilteredSubs.size != 2) {
+                return@combine unfilteredSubs
+            }
+
+            val info1 = unfilteredSubs[0]
+            val info2 = unfilteredSubs[1]
+            // If both subscriptions are primary, show both
+            if (!info1.isOpportunistic && !info2.isOpportunistic) {
+                return@combine unfilteredSubs
+            }
+
+            // NOTE: at this point, we are now returning a single SubscriptionInfo
+
+            // If carrier required, always show the icon of the primary subscription.
+            // Otherwise, show whichever subscription is currently active for internet.
+            if (carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) {
+                // return the non-opportunistic info
+                return@combine if (info1.isOpportunistic) listOf(info2) else listOf(info1)
+            } else {
+                return@combine if (info1.subscriptionId == activeId) {
+                    listOf(info1)
+                } else {
+                    listOf(info2)
+                }
+            }
+        }
+
+    val isUserSetup: Flow<Boolean> = userSetupRepo.isUserSetupFlow
+
+    /** Vends out new [MobileIconInteractor] for a particular subId */
+    fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+        MobileIconInteractorImpl(mobileSubscriptionFlowForSubId(subId))
+
+    /**
+     * Create a new flow for a given subscription ID, which usually maps 1:1 with mobile connections
+     */
+    private fun mobileSubscriptionFlowForSubId(subId: Int): Flow<MobileSubscriptionModel> =
+        mobileSubscriptionRepo.getFlowForSubId(subId)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
new file mode 100644
index 0000000..380017c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/MobileUiAdapter.kt
@@ -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.statusbar.pipeline.mobile.ui
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * This class is intended to provide a context to collect on the
+ * [MobileIconsInteractor.filteredSubscriptions] data source and supply a state flow that can
+ * control [StatusBarIconController] to keep the old UI in sync with the new data source.
+ *
+ * It also provides a mechanism to create a top-level view model for each IconManager to know about
+ * the list of available mobile lines of service for which we want to show icons.
+ */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class MobileUiAdapter
+@Inject
+constructor(
+    interactor: MobileIconsInteractor,
+    private val iconController: StatusBarIconController,
+    private val iconsViewModelFactory: MobileIconsViewModel.Factory,
+    @Application scope: CoroutineScope,
+) {
+    private val mobileSubIds: Flow<List<Int>> =
+        interactor.filteredSubscriptions.mapLatest { infos ->
+            infos.map { subscriptionInfo -> subscriptionInfo.subscriptionId }
+        }
+
+    /**
+     * We expose the list of tracked subscriptions as a flow of a list of ints, where each int is
+     * the subscriptionId of the relevant subscriptions. These act as a key into the layouts which
+     * house the mobile infos.
+     *
+     * NOTE: this should go away as the view presenter learns more about this data pipeline
+     */
+    private val mobileSubIdsState: StateFlow<List<Int>> =
+        mobileSubIds
+            .onEach {
+                // Notify the icon controller here so that it knows to add icons
+                iconController.setNewMobileIconSubIds(it)
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+
+    /**
+     * Create a MobileIconsViewModel for a given [IconManager], and bind it to to the manager's
+     * lifecycle. This will start collecting on [mobileSubIdsState] and link our new pipeline with
+     * the old view system.
+     */
+    fun createMobileIconsViewModel(): MobileIconsViewModel =
+        iconsViewModelFactory.create(mobileSubIdsState)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
new file mode 100644
index 0000000..1405b05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.ui.binder
+
+import android.content.res.ColorStateList
+import android.view.ViewGroup
+import android.widget.ImageView
+import androidx.core.view.isVisible
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.settingslib.graph.SignalDrawable
+import com.android.systemui.R
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
+
+object MobileIconBinder {
+    /** Binds the view to the view-model, continuing to update the former based on the latter */
+    @JvmStatic
+    fun bind(
+        view: ViewGroup,
+        viewModel: MobileIconViewModel,
+    ) {
+        val iconView = view.requireViewById<ImageView>(R.id.mobile_signal)
+        val mobileDrawable = SignalDrawable(view.context).also { iconView.setImageDrawable(it) }
+
+        view.isVisible = true
+        iconView.isVisible = true
+
+        view.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.STARTED) {
+                // Set the icon for the triangle
+                launch {
+                    viewModel.iconId.distinctUntilChanged().collect { iconId ->
+                        mobileDrawable.level = iconId
+                    }
+                }
+
+                // Set the tint
+                launch {
+                    viewModel.tint.collect { tint ->
+                        iconView.imageTintList = ColorStateList.valueOf(tint)
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt
new file mode 100644
index 0000000..e7d5ee2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconsBinder.kt
@@ -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.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.binder
+
+import android.view.View
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
+
+object MobileIconsBinder {
+    /**
+     * Start this ViewModel collecting on the list of mobile subscriptions in the scope of [view]
+     * which is passed in and managed by [IconManager]. Once the subscription list flow starts
+     * collecting, [MobileUiAdapter] will send updates to the icon manager.
+     */
+    @JvmStatic
+    fun bind(view: View, viewModel: MobileIconsViewModel) {
+        view.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.STARTED) {
+                launch {
+                    viewModel.subscriptionIdsFlow.collect {
+                        // TODO(b/249790733): This is an empty collect, because [MobileUiAdapter]
+                        //  sets up a side-effect in this flow to trigger the methods on
+                        // [StatusBarIconController] which allows for this pipeline to be a data
+                        // source for the mobile icons.
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.kt
new file mode 100644
index 0000000..ec4fa9c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/view/ModernStatusBarMobileView.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.pipeline.mobile.ui.view
+
+import android.content.Context
+import android.graphics.Rect
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import com.android.systemui.R
+import com.android.systemui.statusbar.BaseStatusBarFrameLayout
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.pipeline.mobile.ui.binder.MobileIconBinder
+import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconViewModel
+import java.util.ArrayList
+
+class ModernStatusBarMobileView(
+    context: Context,
+    attrs: AttributeSet?,
+) : BaseStatusBarFrameLayout(context, attrs) {
+
+    private lateinit var slot: String
+    override fun getSlot() = slot
+
+    override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
+        // TODO
+    }
+
+    override fun setStaticDrawableColor(color: Int) {
+        // TODO
+    }
+
+    override fun setDecorColor(color: Int) {
+        // TODO
+    }
+
+    override fun setVisibleState(state: Int, animate: Boolean) {
+        // TODO
+    }
+
+    override fun getVisibleState(): Int {
+        return STATE_ICON
+    }
+
+    override fun isIconVisible(): Boolean {
+        return true
+    }
+
+    companion object {
+
+        /**
+         * Inflates a new instance of [ModernStatusBarMobileView], binds it to [viewModel], and
+         * returns it.
+         */
+        @JvmStatic
+        fun constructAndBind(
+            context: Context,
+            slot: String,
+            viewModel: MobileIconViewModel,
+        ): ModernStatusBarMobileView {
+            return (LayoutInflater.from(context)
+                    .inflate(R.layout.status_bar_mobile_signal_group_new, null)
+                    as ModernStatusBarMobileView)
+                .also {
+                    it.slot = slot
+                    MobileIconBinder.bind(it, viewModel)
+                }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
new file mode 100644
index 0000000..cfabeba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -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.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import android.graphics.Color
+import com.android.settingslib.graph.SignalDrawable
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+
+/**
+ * View model for the state of a single mobile icon. Each [MobileIconViewModel] will keep watch over
+ * a single line of service via [MobileIconInteractor] and update the UI based on that
+ * subscription's information.
+ *
+ * There will be exactly one [MobileIconViewModel] per filtered subscription offered from
+ * [MobileIconsInteractor.filteredSubscriptions]
+ *
+ * TODO: figure out where carrier merged and VCN models go (probably here?)
+ */
+class MobileIconViewModel
+constructor(
+    val subscriptionId: Int,
+    iconInteractor: MobileIconInteractor,
+    logger: ConnectivityPipelineLogger,
+) {
+    /** An int consumable by [SignalDrawable] for display */
+    var iconId: Flow<Int> =
+        combine(iconInteractor.level, iconInteractor.numberOfLevels, iconInteractor.cutOut) {
+                level,
+                numberOfLevels,
+                cutOut ->
+                SignalDrawable.getState(level, numberOfLevels, cutOut)
+            }
+            .distinctUntilChanged()
+            .logOutputChange(logger, "iconId($subscriptionId)")
+
+    var tint: Flow<Int> = flowOf(Color.CYAN)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
new file mode 100644
index 0000000..24c1db9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconsViewModel.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(InternalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel
+
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
+import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import javax.inject.Inject
+import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * View model for describing the system's current mobile cellular connections. The result is a list
+ * of [MobileIconViewModel]s which describe the individual icons and can be bound to
+ * [ModernStatusBarMobileView]
+ */
+class MobileIconsViewModel
+@Inject
+constructor(
+    val subscriptionIdsFlow: Flow<List<Int>>,
+    private val interactor: MobileIconsInteractor,
+    private val logger: ConnectivityPipelineLogger,
+) {
+    /** TODO: do we need to cache these? */
+    fun viewModelForSub(subId: Int): MobileIconViewModel =
+        MobileIconViewModel(
+            subId,
+            interactor.createMobileConnectionInteractorForSubId(subId),
+            logger
+        )
+
+    class Factory
+    @Inject
+    constructor(
+        private val interactor: MobileIconsInteractor,
+        private val logger: ConnectivityPipelineLogger,
+    ) {
+        fun create(subscriptionIdsFlow: Flow<List<Int>>): MobileIconsViewModel {
+            return MobileIconsViewModel(
+                subscriptionIdsFlow,
+                interactor,
+                logger,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
new file mode 100644
index 0000000..118b94c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.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.statusbar.pipeline.shared
+
+import android.telephony.TelephonyManager
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * An object storing constants that are used for calculating connectivity icons.
+ *
+ * Stored in a class for logging purposes.
+ */
+@SysUISingleton
+class ConnectivityConstants
+@Inject
+constructor(dumpManager: DumpManager, telephonyManager: TelephonyManager) : Dumpable {
+    init {
+        dumpManager.registerDumpable("$SB_LOGGING_TAG:ConnectivityConstants", this)
+    }
+
+    /** True if this device has the capability for data connections and false otherwise. */
+    val hasDataCapabilities = telephonyManager.isDataCapable
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.apply { println("hasDataCapabilities=$hasDataCapabilities") }
+    }
+}
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 88d8a86..dbb1aa5 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
@@ -33,6 +33,20 @@
 ) {
     /**
      * Logs a change in one of the **raw inputs** to the connectivity pipeline.
+     *
+     * Use this method for inputs that don't have any extra information besides their callback name.
+     */
+    fun logInputChange(callbackName: String) {
+        buffer.log(
+            SB_LOGGING_TAG,
+            LogLevel.INFO,
+            { str1 = callbackName },
+            { "Input: $str1" }
+        )
+    }
+
+    /**
+     * Logs a change in one of the **raw inputs** to the connectivity pipeline.
      */
     fun logInputChange(callbackName: String, changeInfo: String?) {
         buffer.log(
@@ -128,12 +142,36 @@
         const val SB_LOGGING_TAG = "SbConnectivity"
 
         /**
+         * Log a change in one of the **inputs** to the connectivity pipeline.
+         */
+        fun Flow<Unit>.logInputChange(
+            logger: ConnectivityPipelineLogger,
+            inputParamName: String,
+        ): Flow<Unit> {
+            return this.onEach { logger.logInputChange(inputParamName) }
+        }
+
+        /**
+         * Log a change in one of the **inputs** to the connectivity pipeline.
+         *
+         * @param prettyPrint an optional function to transform the value into a readable string.
+         *   [toString] is used if no custom function is provided.
+         */
+        fun <T> Flow<T>.logInputChange(
+            logger: ConnectivityPipelineLogger,
+            inputParamName: String,
+            prettyPrint: (T) -> String = { it.toString() }
+        ): Flow<T> {
+            return this.onEach {logger.logInputChange(inputParamName, prettyPrint(it)) }
+        }
+
+        /**
          * Log a change in one of the **outputs** to the connectivity pipeline.
          *
          * @param prettyPrint an optional function to transform the value into a readable string.
          *   [toString] is used if no custom function is provided.
          */
-        fun <T : Any> Flow<T>.logOutputChange(
+        fun <T> Flow<T>.logOutputChange(
                 logger: ConnectivityPipelineLogger,
                 outputParamName: String,
                 prettyPrint: (T) -> String = { it.toString() }
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 103f3fc..681cf72 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
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.pipeline.wifi.data.repository
 
 import android.annotation.SuppressLint
+import android.content.IntentFilter
 import android.net.ConnectivityManager
 import android.net.Network
 import android.net.NetworkCapabilities
@@ -30,51 +31,87 @@
 import android.net.wifi.WifiManager.TrafficStateCallback
 import android.util.Log
 import com.android.settingslib.Utils
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 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.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.stateIn
 
-/**
- * Provides data related to the wifi state.
- */
+/** Provides data related to the wifi state. */
 interface WifiRepository {
-    /**
-     * Observable for the current wifi network.
-     */
-    val wifiNetwork: Flow<WifiNetworkModel>
+    /** Observable for the current wifi enabled status. */
+    val isWifiEnabled: StateFlow<Boolean>
 
-    /**
-     * Observable for the current wifi network activity.
-     */
-    val wifiActivity: Flow<WifiActivityModel>
+    /** Observable for the current wifi network. */
+    val wifiNetwork: StateFlow<WifiNetworkModel>
+
+    /** Observable for the current wifi network activity. */
+    val wifiActivity: StateFlow<WifiActivityModel>
 }
 
 /** Real implementation of [WifiRepository]. */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 @SuppressLint("MissingPermission")
 class WifiRepositoryImpl @Inject constructor(
+    broadcastDispatcher: BroadcastDispatcher,
     connectivityManager: ConnectivityManager,
     logger: ConnectivityPipelineLogger,
     @Main mainExecutor: Executor,
     @Application scope: CoroutineScope,
     wifiManager: WifiManager?,
 ) : WifiRepository {
-    override val wifiNetwork: Flow<WifiNetworkModel> = conflatedCallbackFlow {
+
+    private val wifiStateChangeEvents: Flow<Unit> = broadcastDispatcher.broadcastFlow(
+        IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)
+    )
+        .logInputChange(logger, "WIFI_STATE_CHANGED_ACTION intent")
+
+    private val wifiNetworkChangeEvents: MutableSharedFlow<Unit> =
+        MutableSharedFlow(extraBufferCapacity = 1)
+
+    override val isWifiEnabled: StateFlow<Boolean> =
+        if (wifiManager == null) {
+            MutableStateFlow(false).asStateFlow()
+        } else {
+            // Because [WifiManager] doesn't expose a wifi enabled change listener, we do it
+            // internally by fetching [WifiManager.isWifiEnabled] whenever we think the state may
+            // have changed.
+            merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
+                .mapLatest { wifiManager.isWifiEnabled }
+                .distinctUntilChanged()
+                .logOutputChange(logger, "enabled")
+                .stateIn(
+                    scope = scope,
+                    started = SharingStarted.WhileSubscribed(),
+                    initialValue = wifiManager.isWifiEnabled
+                )
+        }
+
+    override val wifiNetwork: StateFlow<WifiNetworkModel> = conflatedCallbackFlow {
         var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
 
         val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
@@ -84,6 +121,8 @@
             ) {
                 logger.logOnCapabilitiesChanged(network, networkCapabilities)
 
+                wifiNetworkChangeEvents.tryEmit(Unit)
+
                 val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
                 if (wifiInfo?.isPrimary == true) {
                     val wifiNetworkModel = createWifiNetworkModel(
@@ -104,6 +143,9 @@
 
             override fun onLost(network: Network) {
                 logger.logOnLost(network)
+
+                wifiNetworkChangeEvents.tryEmit(Unit)
+
                 val wifi = currentWifi
                 if (wifi is WifiNetworkModel.Active && wifi.networkId == network.getNetId()) {
                     val newNetworkModel = WifiNetworkModel.Inactive
@@ -132,7 +174,7 @@
             initialValue = WIFI_NETWORK_DEFAULT
         )
 
-    override val wifiActivity: Flow<WifiActivityModel> =
+    override val wifiActivity: StateFlow<WifiActivityModel> =
             if (wifiManager == null) {
                 Log.w(SB_LOGGING_TAG, "Null WifiManager; skipping activity callback")
                 flowOf(ACTIVITY_DEFAULT)
@@ -142,13 +184,15 @@
                         logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
                         trySend(trafficStateToWifiActivityModel(state))
                     }
-
-                    trySend(ACTIVITY_DEFAULT)
                     wifiManager.registerTrafficStateCallback(mainExecutor, callback)
-
                     awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
                 }
             }
+                .stateIn(
+                    scope,
+                    started = SharingStarted.WhileSubscribed(),
+                    initialValue = ACTIVITY_DEFAULT
+                )
 
     companion object {
         val ACTIVITY_DEFAULT = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
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 952525d..04b17ed 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
@@ -22,9 +22,10 @@
 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 com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
 
 /**
@@ -38,7 +39,11 @@
     connectivityRepository: ConnectivityRepository,
     wifiRepository: WifiRepository,
 ) {
-    private val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
+    /**
+     * The SSID (service set identifier) of the wifi network. Null if we don't have a network, or
+     * have a network but no valid SSID.
+     */
+    val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
         when (info) {
             is WifiNetworkModel.Inactive -> null
             is WifiNetworkModel.CarrierMerged -> null
@@ -51,17 +56,17 @@
         }
     }
 
+    /** Our current enabled status. */
+    val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled
+
     /** Our current wifi network. See [WifiNetworkModel]. */
     val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
 
+    /** Our current wifi activity. See [WifiActivityModel]. */
+    val activity: StateFlow<WifiActivityModel> = wifiRepository.wifiActivity
+
     /** 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(wifiRepository.wifiActivity, ssid) { activity, ssid ->
-            activity.hasActivityIn && ssid != null
-        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
index a19d1bd..0eb4b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
@@ -41,9 +41,14 @@
     /** True if we should show the activityIn/activityOut icons and false otherwise. */
     val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
 
+    /** True if we should always show the wifi icon when wifi is enabled and false otherwise. */
+    val alwaysShowIconIfEnabled =
+        context.resources.getBoolean(R.bool.config_showWifiIndicatorWhenEnabled)
+
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.apply {
             println("shouldShowActivityConfig=$shouldShowActivityConfig")
+            println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled")
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
index 44c0496..5746106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.systemui.statusbar.pipeline.wifi.shared.model
 
-/**
- * Provides information on the current wifi activity.
- */
+/** Provides information on the current wifi activity. */
 data class WifiActivityModel(
     /** True if the wifi has activity in (download). */
     val hasActivityIn: Boolean,
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 4fad327..273be63 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
@@ -26,8 +26,15 @@
 import com.android.systemui.R
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
 import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.launch
@@ -41,40 +48,111 @@
  */
 @OptIn(InternalCoroutinesApi::class)
 object WifiViewBinder {
-    /** Binds the view to the view-model, continuing to update the former based on the latter. */
+
+    /**
+     * Defines interface for an object that acts as the binding between the view and its view-model.
+     *
+     * Users of the [WifiViewBinder] class should use this to control the binder after it is bound.
+     */
+    interface Binding {
+        /** Returns true if the wifi icon should be visible and false otherwise. */
+        fun getShouldIconBeVisible(): Boolean
+
+        /** Notifies that the visibility state has changed. */
+        fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int)
+    }
+
+    /**
+     * Binds the view to the appropriate view-model based on the given location. The view will
+     * continue to be updated following updates from the view-model.
+     */
     @JvmStatic
     fun bind(
         view: ViewGroup,
-        viewModel: WifiViewModel,
-    ) {
+        wifiViewModel: WifiViewModel,
+        location: StatusBarLocation,
+    ): Binding {
+        return when (location) {
+            StatusBarLocation.HOME -> bind(view, wifiViewModel.home)
+            StatusBarLocation.KEYGUARD -> bind(view, wifiViewModel.keyguard)
+            StatusBarLocation.QS -> bind(view, wifiViewModel.qs)
+        }
+    }
+
+    /** Binds the view to the view-model, continuing to update the former based on the latter. */
+    @JvmStatic
+    private fun bind(
+        view: ViewGroup,
+        viewModel: LocationBasedWifiViewModel,
+    ): Binding {
+        val groupView = view.requireViewById<ViewGroup>(R.id.wifi_group)
         val iconView = view.requireViewById<ImageView>(R.id.wifi_signal)
+        val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
+        val activityInView = view.requireViewById<ImageView>(R.id.wifi_in)
+        val activityOutView = view.requireViewById<ImageView>(R.id.wifi_out)
+        val activityContainerView = view.requireViewById<View>(R.id.inout_container)
 
         view.isVisible = true
         iconView.isVisible = true
 
+        // TODO(b/238425913): We should log this visibility state.
+        @StatusBarIconView.VisibleState
+        val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
+
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
-                    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.
+                    visibilityState.collect { visibilityState ->
+                        groupView.isVisible = visibilityState == STATE_ICON
+                        dotView.isVisible = visibilityState == STATE_DOT
+                    }
+                }
+
+                launch {
+                    viewModel.wifiIcon.collect { wifiIcon ->
                         view.isVisible = wifiIcon != null
-                        wifiIcon?.let {
-                            IconViewBinder.bind(wifiIcon, iconView)
-                        }
+                        wifiIcon?.let { IconViewBinder.bind(wifiIcon, iconView) }
                     }
                 }
 
                 launch {
                     viewModel.tint.collect { tint ->
-                        iconView.imageTintList = ColorStateList.valueOf(tint)
+                        val tintList = ColorStateList.valueOf(tint)
+                        iconView.imageTintList = tintList
+                        activityInView.imageTintList = tintList
+                        activityOutView.imageTintList = tintList
+                        dotView.setDecorColor(tint)
+                    }
+                }
+
+                launch {
+                    viewModel.isActivityInViewVisible.distinctUntilChanged().collect { visible ->
+                        activityInView.isVisible = visible
+                    }
+                }
+
+                launch {
+                    viewModel.isActivityOutViewVisible.distinctUntilChanged().collect { visible ->
+                        activityOutView.isVisible = visible
+                    }
+                }
+
+                launch {
+                    viewModel.isActivityContainerVisible.distinctUntilChanged().collect { visible ->
+                        activityContainerView.isVisible = visible
                     }
                 }
             }
         }
 
-        // TODO(b/238425913): Hook up to [viewModel] to render actual changes to the wifi icon.
+        return object : Binding {
+            override fun getShouldIconBeVisible(): Boolean {
+                return viewModel.wifiIcon.value != null
+            }
+
+            override fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) {
+                visibilityState.value = state
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
index c14a897..0cd9bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
@@ -19,10 +19,14 @@
 import android.content.Context
 import android.graphics.Rect
 import android.util.AttributeSet
+import android.view.Gravity
 import android.view.LayoutInflater
 import com.android.systemui.R
-import com.android.systemui.statusbar.BaseStatusBarWifiView
-import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.BaseStatusBarFrameLayout
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
 
@@ -33,9 +37,20 @@
 class ModernStatusBarWifiView(
     context: Context,
     attrs: AttributeSet?
-) : BaseStatusBarWifiView(context, attrs) {
+) : BaseStatusBarFrameLayout(context, attrs) {
 
     private lateinit var slot: String
+    private lateinit var binding: WifiViewBinder.Binding
+
+    @StatusBarIconView.VisibleState
+    private var iconVisibleState: Int = STATE_HIDDEN
+        set(value) {
+            if (field == value) {
+                return
+            }
+            field = value
+            binding.onVisibilityStateChanged(value)
+        }
 
     override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
         // TODO(b/238425913)
@@ -51,42 +66,64 @@
         // TODO(b/238425913)
     }
 
-    override fun setVisibleState(state: Int, animate: Boolean) {
-        // TODO(b/238425913)
+    override fun setVisibleState(@StatusBarIconView.VisibleState state: Int, animate: Boolean) {
+        iconVisibleState = state
     }
 
+    @StatusBarIconView.VisibleState
     override fun getVisibleState(): Int {
-        // TODO(b/238425913)
-        return STATE_ICON
+        return iconVisibleState
     }
 
     override fun isIconVisible(): Boolean {
-        // TODO(b/238425913)
-        return true
+        return binding.getShouldIconBeVisible()
     }
 
-    /** Set the slot name for this view. */
-    private fun setSlot(slotName: String) {
-        this.slot = slotName
+    private fun initView(
+        slotName: String,
+        wifiViewModel: WifiViewModel,
+        location: StatusBarLocation,
+    ) {
+        slot = slotName
+        initDotView()
+        binding = WifiViewBinder.bind(this, wifiViewModel, location)
+    }
+
+    // Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView].
+    private fun initDotView() {
+        // TODO(b/238425913): Could we just have this dot view be part of
+        //   R.layout.new_status_bar_wifi_group with a dot drawable so we don't need to inflate it
+        //   manually? Would that not work with animations?
+        val dotView = StatusBarIconView(mContext, slot, null).also {
+            it.id = R.id.status_bar_dot
+            // Hard-code this view to always be in the DOT state so that whenever it's visible it
+            // will show a dot
+            it.visibleState = STATE_DOT
+        }
+
+        val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size)
+        val lp = LayoutParams(width, width)
+        lp.gravity = Gravity.CENTER_VERTICAL or Gravity.START
+        addView(dotView, lp)
     }
 
     companion object {
         /**
-         * Inflates a new instance of [ModernStatusBarWifiView], binds it to [viewModel], and
+         * Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and
          * returns it.
          */
         @JvmStatic
         fun constructAndBind(
             context: Context,
             slot: String,
-            viewModel: WifiViewModel,
+            wifiViewModel: WifiViewModel,
+            location: StatusBarLocation,
         ): ModernStatusBarWifiView {
             return (
                 LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
                     as ModernStatusBarWifiView
                 ).also {
-                    it.setSlot(slot)
-                    WifiViewBinder.bind(it, viewModel)
+                    it.initView(slot, wifiViewModel, location)
                 }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/HomeWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/HomeWifiViewModel.kt
new file mode 100644
index 0000000..40f948f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/HomeWifiViewModel.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/**
+ * A view model for the wifi icon shown on the "home" page (aka, when the device is unlocked and not
+ * showing the shade, so the user is on the home-screen, or in an app).
+ */
+class HomeWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiIcon: StateFlow<Icon.Resource?>,
+    isActivityInViewVisible: Flow<Boolean>,
+    isActivityOutViewVisible: Flow<Boolean>,
+    isActivityContainerVisible: Flow<Boolean>,
+) :
+    LocationBasedWifiViewModel(
+        statusBarPipelineFlags,
+        debugTint = Color.CYAN,
+        wifiIcon,
+        isActivityInViewVisible,
+        isActivityOutViewVisible,
+        isActivityContainerVisible,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/KeyguardWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/KeyguardWifiViewModel.kt
new file mode 100644
index 0000000..9642ac4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/KeyguardWifiViewModel.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.systemui.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/** A view model for the wifi icon shown on keyguard (lockscreen). */
+class KeyguardWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiIcon: StateFlow<Icon.Resource?>,
+    isActivityInViewVisible: Flow<Boolean>,
+    isActivityOutViewVisible: Flow<Boolean>,
+    isActivityContainerVisible: Flow<Boolean>,
+) :
+    LocationBasedWifiViewModel(
+        statusBarPipelineFlags,
+        debugTint = Color.MAGENTA,
+        wifiIcon,
+        isActivityInViewVisible,
+        isActivityOutViewVisible,
+        isActivityContainerVisible,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
new file mode 100644
index 0000000..e23f8c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.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.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOf
+
+/**
+ * A view model for a wifi icon in a specific location. This allows us to control parameters that
+ * are location-specific (for example, different tints of the icon in different locations).
+ *
+ * Must be subclassed for each distinct location.
+ */
+abstract class LocationBasedWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    debugTint: Int,
+
+    /** The wifi icon that should be displayed. Null if we shouldn't display any icon. */
+    val wifiIcon: StateFlow<Icon.Resource?>,
+
+    /** True if the activity in view should be visible. */
+    val isActivityInViewVisible: Flow<Boolean>,
+
+    /** True if the activity out view should be visible. */
+    val isActivityOutViewVisible: Flow<Boolean>,
+
+    /** True if the activity container view should be visible. */
+    val isActivityContainerVisible: Flow<Boolean>,
+) {
+    /** The color that should be used to tint the icon. */
+    val tint: Flow<Int> =
+        flowOf(
+            if (statusBarPipelineFlags.useNewPipelineDebugColoring()) {
+                debugTint
+            } else {
+                DEFAULT_TINT
+            }
+        )
+
+    companion object {
+        /**
+         * A default icon tint.
+         *
+         * TODO(b/238425913): The tint is actually controlled by
+         * [com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager]. We
+         * should use that logic instead of white as a default.
+         */
+        private const val DEFAULT_TINT = Color.WHITE
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/QsWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/QsWifiViewModel.kt
new file mode 100644
index 0000000..0ddf90e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/QsWifiViewModel.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.systemui.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/** A view model for the wifi icon shown in quick settings (when the shade is pulled down). */
+class QsWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiIcon: StateFlow<Icon.Resource?>,
+    isActivityInViewVisible: Flow<Boolean>,
+    isActivityOutViewVisible: Flow<Boolean>,
+    isActivityContainerVisible: Flow<Boolean>,
+) :
+    LocationBasedWifiViewModel(
+        statusBarPipelineFlags,
+        debugTint = Color.GREEN,
+        wifiIcon,
+        isActivityInViewVisible,
+        isActivityOutViewVisible,
+        isActivityContainerVisible,
+    )
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 3c243ac..ebbd77b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -17,7 +17,6 @@
 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
@@ -26,107 +25,185 @@
 import com.android.systemui.R
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 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.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 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.shared.model.WifiActivityModel
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
 
 /**
  * Models the UI state for the status bar wifi icon.
+ *
+ * This class exposes three view models, one per status bar location:
+ *  - [home]
+ *  - [keyguard]
+ *  - [qs]
+ *  In order to get the UI state for the wifi icon, you must use one of those view models (whichever
+ *  is correct for your location).
+ *
+ * Internally, this class maintains the current state of the wifi icon and notifies those three
+ * view models of any changes.
  */
-class WifiViewModel @Inject constructor(
-    statusBarPipelineFlags: StatusBarPipelineFlags,
-    private val constants: WifiConstants,
+@SysUISingleton
+class WifiViewModel
+@Inject
+constructor(
+    connectivityConstants: ConnectivityConstants,
     private val context: Context,
-    private val logger: ConnectivityPipelineLogger,
-    private val interactor: WifiInteractor,
+    logger: ConnectivityPipelineLogger,
+    interactor: WifiInteractor,
+    @Application private val scope: CoroutineScope,
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiConstants: WifiConstants,
 ) {
     /**
-     * The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
+     * Returns the drawable resource ID to use for the wifi icon based on the given network.
+     * Null if we can't compute the icon.
      */
     @DrawableRes
-    private val iconResId: Flow<Int?> = interactor.wifiNetwork.map {
-        when (it) {
+    private fun WifiNetworkModel.iconResId(): Int? {
+        return when (this) {
             is WifiNetworkModel.CarrierMerged -> null
             is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
             is WifiNetworkModel.Active ->
                 when {
-                    it.level == null -> null
-                    it.isValidated -> WIFI_FULL_ICONS[it.level]
-                    else -> WIFI_NO_INTERNET_ICONS[it.level]
+                    this.level == null -> null
+                    this.isValidated -> WIFI_FULL_ICONS[this.level]
+                    else -> WIFI_NO_INTERNET_ICONS[this.level]
                 }
         }
     }
 
-    /** The content description for the wifi icon. */
-    private val contentDescription: Flow<ContentDescription?> = interactor.wifiNetwork.map {
-        when (it) {
+    /**
+     * Returns the content description for the wifi icon based on the given network.
+     * Null if we can't compute the content description.
+     */
+    private fun WifiNetworkModel.contentDescription(): ContentDescription? {
+        return when (this) {
             is WifiNetworkModel.CarrierMerged -> null
             is WifiNetworkModel.Inactive ->
                 ContentDescription.Loaded(
                     "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
                 )
             is WifiNetworkModel.Active ->
-                when (it.level) {
+                when (this.level) {
                     null -> null
                     else -> {
-                        val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[it.level])
+                        val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
                         when {
-                            it.isValidated -> ContentDescription.Loaded(levelDesc)
-                            else -> ContentDescription.Loaded(
-                                "$levelDesc,${context.getString(NO_INTERNET)}"
-                            )
+                            this.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(
+    /** The wifi icon that should be displayed. Null if we shouldn't display any icon. */
+    private val wifiIcon: StateFlow<Icon.Resource?> =
+        combine(
+            interactor.isEnabled,
             interactor.isForceHidden,
-            iconResId,
-            contentDescription,
-        ) { isForceHidden, iconResId, contentDescription ->
-            when {
-                isForceHidden ||
-                    iconResId == null ||
-                    iconResId <= 0 -> null
-                else -> Icon.Resource(iconResId, contentDescription)
+            interactor.wifiNetwork,
+        ) { isEnabled, isForceHidden, wifiNetwork ->
+            if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) {
+                return@combine null
+            }
+
+            val iconResId = wifiNetwork.iconResId() ?: return@combine null
+            val icon = Icon.Resource(iconResId, wifiNetwork.contentDescription())
+
+            return@combine when {
+                wifiConstants.alwaysShowIconIfEnabled -> icon
+                !connectivityConstants.hasDataCapabilities -> icon
+                wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon
+                else -> null
             }
         }
+        .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
 
-    /**
-     * True if the activity in icon should be displayed and false otherwise.
-     */
-    val isActivityInVisible: Flow<Boolean>
-        get() =
-            if (!constants.shouldShowActivityConfig) {
-                flowOf(false)
-            } else {
-                interactor.hasActivityIn
+    /** The wifi activity status. Null if we shouldn't display the activity status. */
+    private val activity: Flow<WifiActivityModel?> =
+        if (!wifiConstants.shouldShowActivityConfig) {
+            flowOf(null)
+        } else {
+            combine(interactor.activity, interactor.ssid) { activity, ssid ->
+                when (ssid) {
+                    null -> null
+                    else -> activity
+                }
             }
-                .logOutputChange(logger, "activityInVisible")
+        }
+        .distinctUntilChanged()
+        .logOutputChange(logger, "activity")
+        .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
 
-    /** The tint that should be applied to the icon. */
-    val tint: Flow<Int> = if (!statusBarPipelineFlags.useNewPipelineDebugColoring()) {
-        emptyFlow()
-    } else {
-        flowOf(Color.CYAN)
-    }
+    private val isActivityInViewVisible: Flow<Boolean> =
+         activity
+             .map { it?.hasActivityIn == true }
+             .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    private val isActivityOutViewVisible: Flow<Boolean> =
+       activity
+           .map { it?.hasActivityOut == true }
+           .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    private val isActivityContainerVisible: Flow<Boolean> =
+         combine(isActivityInViewVisible, isActivityOutViewVisible) { activityIn, activityOut ->
+                    activityIn || activityOut
+                }
+             .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    /** A view model for the status bar on the home screen. */
+    val home: HomeWifiViewModel =
+        HomeWifiViewModel(
+            statusBarPipelineFlags,
+            wifiIcon,
+            isActivityInViewVisible,
+            isActivityOutViewVisible,
+            isActivityContainerVisible,
+        )
+
+    /** A view model for the status bar on keyguard. */
+    val keyguard: KeyguardWifiViewModel =
+        KeyguardWifiViewModel(
+            statusBarPipelineFlags,
+            wifiIcon,
+            isActivityInViewVisible,
+            isActivityOutViewVisible,
+            isActivityContainerVisible,
+        )
+
+    /** A view model for the status bar in quick settings. */
+    val qs: QsWifiViewModel =
+        QsWifiViewModel(
+            statusBarPipelineFlags,
+            wifiIcon,
+            isActivityInViewVisible,
+            isActivityOutViewVisible,
+            isActivityContainerVisible,
+        )
 
     companion object {
         @StringRes
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java
new file mode 100644
index 0000000..ba5fa1d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AospPolicyModule.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.PowerManager;
+
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.power.EnhancedEstimates;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * com.android.systemui.statusbar.policy related providers that others may want to override.
+ */
+@Module
+public class AospPolicyModule {
+    @Provides
+    @SysUISingleton
+    static BatteryController provideBatteryController(
+            Context context,
+            EnhancedEstimates enhancedEstimates,
+            PowerManager powerManager,
+            BroadcastDispatcher broadcastDispatcher,
+            DemoModeController demoModeController,
+            DumpManager dumpManager,
+            @Main Handler mainHandler,
+            @Background Handler bgHandler) {
+        BatteryController bC = new BatteryControllerImpl(
+                context,
+                enhancedEstimates,
+                powerManager,
+                broadcastDispatcher,
+                demoModeController,
+                dumpManager,
+                mainHandler,
+                bgHandler);
+        bC.init();
+        return bC;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index f2ee858..21a8300 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -107,7 +107,7 @@
         boolean allSimsMissing = true;
         CharSequence displayText = null;
 
-        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false);
+        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getFilteredSubscriptionInfo();
         final int N = subs.size();
         for (int i = 0; i < N; i++) {
             int subId = subs.get(i).getSubscriptionId();
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 f4d08e0..437d4d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -435,7 +435,7 @@
         }
 
         @Override
-        public void onKeyguardVisibilityChanged(boolean showing) {
+        public void onKeyguardVisibilityChanged(boolean visible) {
             update(false /* updateAlways */);
         }
 
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 0995a00..494a4bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -91,11 +91,11 @@
     private final KeyguardUpdateMonitorCallback mInfoCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
-                public void onKeyguardVisibilityChanged(boolean showing) {
-                    if (DEBUG) Log.d(TAG, String.format("onKeyguardVisibilityChanged %b", showing));
+                public void onKeyguardVisibilityChanged(boolean visible) {
+                    if (DEBUG) Log.d(TAG, String.format("onKeyguardVisibilityChanged %b", visible));
                     // Any time the keyguard is hidden, try to close the user switcher menu to
                     // restore keyguard to the default state
-                    if (!showing) {
+                    if (!visible) {
                         closeSwitcherIfOpenAndNotSimple(false);
                     }
                 }
@@ -505,7 +505,7 @@
                 v.bind(name, drawable, item.info.id);
             }
             v.setActivated(item.isCurrent);
-            v.setDisabledByAdmin(getController().isDisabledByAdmin(item));
+            v.setDisabledByAdmin(item.isDisabledByAdmin());
             v.setEnabled(item.isSwitchToEnabled);
             UserSwitcherController.setSelectableAlpha(v);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 5a33603..da6d455 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -221,8 +221,10 @@
 
         mEditText.setTextColor(textColor);
         mEditText.setHintTextColor(hintColor);
-        mEditText.getTextCursorDrawable().setColorFilter(
-                accentColor.getDefaultColor(), PorterDuff.Mode.SRC_IN);
+        if (mEditText.getTextCursorDrawable() != null) {
+            mEditText.getTextCursorDrawable().setColorFilter(
+                    accentColor.getDefaultColor(), PorterDuff.Mode.SRC_IN);
+        }
         mContentBackground.setColor(editBgColor);
         mContentBackground.setStroke(stroke, accentColor);
         mDelete.setImageTintList(ColorStateList.valueOf(deleteFgColor));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
index 843c232..146b222 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.kt
@@ -19,7 +19,6 @@
 import android.annotation.UserIdInt
 import android.content.Intent
 import android.view.View
-import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
 import com.android.systemui.Dumpable
 import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower
 import com.android.systemui.user.data.source.UserRecord
@@ -130,12 +129,6 @@
     /** Whether keyguard is showing. */
     val isKeyguardShowing: Boolean
 
-    /** Returns the [EnforcedAdmin] for the given record, or `null` if there isn't one. */
-    fun getEnforcedAdmin(record: UserRecord): EnforcedAdmin?
-
-    /** Returns `true` if the given record is disabled by the admin; `false` otherwise. */
-    fun isDisabledByAdmin(record: UserRecord): Boolean
-
     /** Starts an activity with the given [Intent]. */
     fun startActivity(intent: Intent)
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
index 12834f6..af39eee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerImpl.kt
@@ -17,13 +17,20 @@
 
 package com.android.systemui.statusbar.policy
 
+import android.content.Context
 import android.content.Intent
 import android.view.View
-import com.android.settingslib.RestrictedLockUtils
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.qs.user.UserSwitchDialogController
 import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.domain.interactor.GuestUserInteractor
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
 import dagger.Lazy
 import java.io.PrintWriter
 import java.lang.ref.WeakReference
@@ -31,58 +38,76 @@
 import kotlinx.coroutines.flow.Flow
 
 /** Implementation of [UserSwitcherController]. */
+@SysUISingleton
 class UserSwitcherControllerImpl
 @Inject
 constructor(
-    private val flags: FeatureFlags,
+    @Application private val applicationContext: Context,
+    flags: FeatureFlags,
     @Suppress("DEPRECATION") private val oldImpl: Lazy<UserSwitcherControllerOldImpl>,
+    private val userInteractorLazy: Lazy<UserInteractor>,
+    private val guestUserInteractorLazy: Lazy<GuestUserInteractor>,
+    private val keyguardInteractorLazy: Lazy<KeyguardInteractor>,
+    private val activityStarter: ActivityStarter,
 ) : UserSwitcherController {
 
-    private val isNewImpl: Boolean
-        get() = flags.isEnabled(Flags.REFACTORED_USER_SWITCHER_CONTROLLER)
+    private val useInteractor: Boolean =
+        flags.isEnabled(Flags.USER_CONTROLLER_USES_INTERACTOR) &&
+            !flags.isEnabled(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER)
     private val _oldImpl: UserSwitcherControllerOldImpl
         get() = oldImpl.get()
+    private val userInteractor: UserInteractor by lazy { userInteractorLazy.get() }
+    private val guestUserInteractor: GuestUserInteractor by lazy { guestUserInteractorLazy.get() }
+    private val keyguardInteractor: KeyguardInteractor by lazy { keyguardInteractorLazy.get() }
 
-    private fun notYetImplemented(): Nothing {
-        error("Not yet implemented!")
+    private val callbackCompatMap =
+        mutableMapOf<UserSwitcherController.UserSwitchCallback, UserInteractor.UserCallback>()
+
+    private fun notSupported(): Nothing {
+        error("Not supported in the new implementation!")
     }
 
     override val users: ArrayList<UserRecord>
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                userInteractor.userRecords.value
             } else {
                 _oldImpl.users
             }
 
     override val isSimpleUserSwitcher: Boolean
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                userInteractor.isSimpleUserSwitcher
             } else {
                 _oldImpl.isSimpleUserSwitcher
             }
 
     override fun init(view: View) {
-        if (isNewImpl) {
-            notYetImplemented()
-        } else {
+        if (!useInteractor) {
             _oldImpl.init(view)
         }
     }
 
     override val currentUserRecord: UserRecord?
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                userInteractor.selectedUserRecord.value
             } else {
                 _oldImpl.currentUserRecord
             }
 
     override val currentUserName: String?
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                currentUserRecord?.let {
+                    LegacyUserUiHelper.getUserRecordName(
+                        context = applicationContext,
+                        record = it,
+                        isGuestUserAutoCreated = userInteractor.isGuestUserAutoCreated,
+                        isGuestUserResetting = userInteractor.isGuestUserResetting,
+                    )
+                }
             } else {
                 _oldImpl.currentUserName
             }
@@ -91,8 +116,8 @@
         userId: Int,
         dialogShower: UserSwitchDialogController.DialogShower?
     ) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.selectUser(userId, dialogShower)
         } else {
             _oldImpl.onUserSelected(userId, dialogShower)
         }
@@ -100,24 +125,24 @@
 
     override val isAddUsersFromLockScreenEnabled: Flow<Boolean>
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                notSupported()
             } else {
                 _oldImpl.isAddUsersFromLockScreenEnabled
             }
 
     override val isGuestUserAutoCreated: Boolean
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                userInteractor.isGuestUserAutoCreated
             } else {
                 _oldImpl.isGuestUserAutoCreated
             }
 
     override val isGuestUserResetting: Boolean
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                userInteractor.isGuestUserResetting
             } else {
                 _oldImpl.isGuestUserResetting
             }
@@ -125,40 +150,48 @@
     override fun createAndSwitchToGuestUser(
         dialogShower: UserSwitchDialogController.DialogShower?,
     ) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            notSupported()
         } else {
             _oldImpl.createAndSwitchToGuestUser(dialogShower)
         }
     }
 
     override fun showAddUserDialog(dialogShower: UserSwitchDialogController.DialogShower?) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            notSupported()
         } else {
             _oldImpl.showAddUserDialog(dialogShower)
         }
     }
 
     override fun startSupervisedUserActivity() {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            notSupported()
         } else {
             _oldImpl.startSupervisedUserActivity()
         }
     }
 
     override fun onDensityOrFontScaleChanged() {
-        if (isNewImpl) {
-            notYetImplemented()
-        } else {
+        if (!useInteractor) {
             _oldImpl.onDensityOrFontScaleChanged()
         }
     }
 
     override fun addAdapter(adapter: WeakReference<BaseUserSwitcherAdapter>) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.addCallback(
+                object : UserInteractor.UserCallback {
+                    override fun isEvictable(): Boolean {
+                        return adapter.get() == null
+                    }
+
+                    override fun onUserStateChanged() {
+                        adapter.get()?.notifyDataSetChanged()
+                    }
+                }
+            )
         } else {
             _oldImpl.addAdapter(adapter)
         }
@@ -168,16 +201,19 @@
         record: UserRecord,
         dialogShower: UserSwitchDialogController.DialogShower?,
     ) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.onRecordSelected(record, dialogShower)
         } else {
             _oldImpl.onUserListItemClicked(record, dialogShower)
         }
     }
 
     override fun removeGuestUser(guestUserId: Int, targetUserId: Int) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.removeGuestUser(
+                guestUserId = guestUserId,
+                targetUserId = targetUserId,
+            )
         } else {
             _oldImpl.removeGuestUser(guestUserId, targetUserId)
         }
@@ -188,16 +224,16 @@
         targetUserId: Int,
         forceRemoveGuestOnExit: Boolean
     ) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.exitGuestUser(guestUserId, targetUserId, forceRemoveGuestOnExit)
         } else {
             _oldImpl.exitGuestUser(guestUserId, targetUserId, forceRemoveGuestOnExit)
         }
     }
 
     override fun schedulePostBootGuestCreation() {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            guestUserInteractor.onDeviceBootCompleted()
         } else {
             _oldImpl.schedulePostBootGuestCreation()
         }
@@ -205,63 +241,57 @@
 
     override val isKeyguardShowing: Boolean
         get() =
-            if (isNewImpl) {
-                notYetImplemented()
+            if (useInteractor) {
+                keyguardInteractor.isKeyguardShowing()
             } else {
                 _oldImpl.isKeyguardShowing
             }
 
-    override fun getEnforcedAdmin(record: UserRecord): RestrictedLockUtils.EnforcedAdmin? {
-        return if (isNewImpl) {
-            notYetImplemented()
-        } else {
-            _oldImpl.getEnforcedAdmin(record)
-        }
-    }
-
-    override fun isDisabledByAdmin(record: UserRecord): Boolean {
-        return if (isNewImpl) {
-            notYetImplemented()
-        } else {
-            _oldImpl.isDisabledByAdmin(record)
-        }
-    }
-
     override fun startActivity(intent: Intent) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            activityStarter.startActivity(intent, /* dismissShade= */ false)
         } else {
             _oldImpl.startActivity(intent)
         }
     }
 
     override fun refreshUsers(forcePictureLoadForId: Int) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.refreshUsers()
         } else {
             _oldImpl.refreshUsers(forcePictureLoadForId)
         }
     }
 
     override fun addUserSwitchCallback(callback: UserSwitcherController.UserSwitchCallback) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            val interactorCallback =
+                object : UserInteractor.UserCallback {
+                    override fun onUserStateChanged() {
+                        callback.onUserSwitched()
+                    }
+                }
+            callbackCompatMap[callback] = interactorCallback
+            userInteractor.addCallback(interactorCallback)
         } else {
             _oldImpl.addUserSwitchCallback(callback)
         }
     }
 
     override fun removeUserSwitchCallback(callback: UserSwitcherController.UserSwitchCallback) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            val interactorCallback = callbackCompatMap.remove(callback)
+            if (interactorCallback != null) {
+                userInteractor.removeCallback(interactorCallback)
+            }
         } else {
             _oldImpl.removeUserSwitchCallback(callback)
         }
     }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
-        if (isNewImpl) {
-            notYetImplemented()
+        if (useInteractor) {
+            userInteractor.dump(pw)
         } else {
             _oldImpl.dump(pw, args)
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
index d365aa6..46d2f3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherControllerOldImpl.java
@@ -17,17 +17,13 @@
 
 import static android.os.UserManager.SWITCHABILITY_STATUS_OK;
 
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
 import android.annotation.UserIdInt;
-import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.IActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.UserInfo;
@@ -40,7 +36,6 @@
 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;
@@ -49,17 +44,14 @@
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
-import androidx.collection.SimpleArrayMap;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.util.LatencyTracker;
-import com.android.settingslib.RestrictedLockUtilsInternal;
 import com.android.settingslib.users.UserCreatingDialog;
 import com.android.systemui.GuestResetOrExitSessionReceiver;
 import com.android.systemui.GuestResumeSessionReceiver;
-import com.android.systemui.R;
 import com.android.systemui.SystemUISecondaryUserService;
 import com.android.systemui.animation.DialogCuj;
 import com.android.systemui.animation.DialogLaunchAnimator;
@@ -75,10 +67,12 @@
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower;
 import com.android.systemui.settings.UserTracker;
-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.data.LegacyUserDataHelper;
+import com.android.systemui.user.shared.model.UserActionModel;
+import com.android.systemui.user.ui.dialog.AddUserDialog;
+import com.android.systemui.user.ui.dialog.ExitGuestDialog;
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 
@@ -139,9 +133,6 @@
     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
@@ -334,7 +325,6 @@
 
             for (UserInfo info : infos) {
                 boolean isCurrent = currentId == info.id;
-                boolean switchToEnabled = canSwitchUsers || isCurrent;
                 if (!mUserSwitcherEnabled && !info.isPrimary()) {
                     continue;
                 }
@@ -343,25 +333,22 @@
                     if (info.isGuest()) {
                         // Tapping guest icon triggers remove and a user switch therefore
                         // the icon shouldn't be enabled even if the user is current
-                        guestRecord = new UserRecord(info, null /* picture */,
-                                true /* isGuest */, isCurrent, false /* isAddUser */,
-                                false /* isRestricted */, canSwitchUsers,
-                                false /* isAddSupervisedUser */);
+                        guestRecord = LegacyUserDataHelper.createRecord(
+                                mContext,
+                                mUserManager,
+                                null /* picture */,
+                                info,
+                                isCurrent,
+                                canSwitchUsers);
                     } else if (info.supportsSwitchToByUser()) {
-                        Bitmap picture = bitmaps.get(info.id);
-                        if (picture == null) {
-                            picture = mUserManager.getUserIcon(info.id);
-
-                            if (picture != null) {
-                                int avatarSize = mContext.getResources()
-                                        .getDimensionPixelSize(R.dimen.max_avatar_size);
-                                picture = Bitmap.createScaledBitmap(
-                                        picture, avatarSize, avatarSize, true);
-                            }
-                        }
-                        records.add(new UserRecord(info, picture, false /* isGuest */,
-                                isCurrent, false /* isAddUser */, false /* isRestricted */,
-                                switchToEnabled, false /* isAddSupervisedUser */));
+                        records.add(
+                                LegacyUserDataHelper.createRecord(
+                                        mContext,
+                                        mUserManager,
+                                        bitmaps.get(info.id),
+                                        info,
+                                        isCurrent,
+                                        canSwitchUsers));
                     }
                 }
             }
@@ -372,18 +359,20 @@
                     // we will just use it as an indicator for "Resetting guest...".
                     // Otherwise, default to canSwitchUsers.
                     boolean isSwitchToGuestEnabled = !mGuestIsResetting.get() && canSwitchUsers;
-                    guestRecord = new UserRecord(null /* info */, null /* picture */,
-                            true /* isGuest */, false /* isCurrent */,
-                            false /* isAddUser */, false /* isRestricted */,
-                            isSwitchToGuestEnabled, false /* isAddSupervisedUser */);
-                    checkIfAddUserDisallowedByAdminOnly(guestRecord);
+                    guestRecord = LegacyUserDataHelper.createRecord(
+                            mContext,
+                            currentId,
+                            UserActionModel.ENTER_GUEST_MODE,
+                            false /* isRestricted */,
+                            isSwitchToGuestEnabled);
                     records.add(guestRecord);
                 } else if (canCreateGuest(guestRecord != null)) {
-                    guestRecord = new UserRecord(null /* info */, null /* picture */,
-                            true /* isGuest */, false /* isCurrent */,
-                            false /* isAddUser */, createIsRestricted(), canSwitchUsers,
-                            false /* isAddSupervisedUser */);
-                    checkIfAddUserDisallowedByAdminOnly(guestRecord);
+                    guestRecord = LegacyUserDataHelper.createRecord(
+                            mContext,
+                            currentId,
+                            UserActionModel.ENTER_GUEST_MODE,
+                            false /* isRestricted */,
+                            canSwitchUsers);
                     records.add(guestRecord);
                 }
             } else {
@@ -391,20 +380,23 @@
             }
 
             if (canCreateUser()) {
-                UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
-                        false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
-                        createIsRestricted(), canSwitchUsers,
-                        false /* isAddSupervisedUser */);
-                checkIfAddUserDisallowedByAdminOnly(addUserRecord);
-                records.add(addUserRecord);
+                final UserRecord userRecord = LegacyUserDataHelper.createRecord(
+                        mContext,
+                        currentId,
+                        UserActionModel.ADD_USER,
+                        createIsRestricted(),
+                        canSwitchUsers);
+                records.add(userRecord);
             }
 
             if (canCreateSupervisedUser()) {
-                UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
-                        false /* isGuest */, false /* isCurrent */, false /* isAddUser */,
-                        createIsRestricted(), canSwitchUsers, true /* isAddSupervisedUser */);
-                checkIfAddUserDisallowedByAdminOnly(addUserRecord);
-                records.add(addUserRecord);
+                final UserRecord userRecord = LegacyUserDataHelper.createRecord(
+                        mContext,
+                        currentId,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                        createIsRestricted(),
+                        canSwitchUsers);
+                records.add(userRecord);
             }
 
             mUiExecutor.execute(() -> {
@@ -591,12 +583,23 @@
         showExitGuestDialog(id, isGuestEphemeral, newId, dialogShower);
     }
 
-    private void showExitGuestDialog(int id, boolean isGuestEphemeral,
-                        int targetId, DialogShower dialogShower) {
+    private void showExitGuestDialog(
+            int id,
+            boolean isGuestEphemeral,
+            int targetId,
+            DialogShower dialogShower) {
         if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
             mExitGuestDialog.cancel();
         }
-        mExitGuestDialog = new ExitGuestDialog(mContext, id, isGuestEphemeral, targetId);
+        mExitGuestDialog = new ExitGuestDialog(
+                mContext,
+                id,
+                isGuestEphemeral,
+                targetId,
+                mKeyguardStateController.isShowing(),
+                mFalsingManager,
+                mDialogLaunchAnimator,
+                this::exitGuestUser);
         if (dialogShower != null) {
             dialogShower.showDialog(mExitGuestDialog, new DialogCuj(
                     InteractionJankMonitor.CUJ_USER_DIALOG_OPEN,
@@ -622,7 +625,15 @@
         if (mAddUserDialog != null && mAddUserDialog.isShowing()) {
             mAddUserDialog.cancel();
         }
-        mAddUserDialog = new AddUserDialog(mContext);
+        final UserInfo currentUser = mUserTracker.getUserInfo();
+        mAddUserDialog = new AddUserDialog(
+                mContext,
+                currentUser.getUserHandle(),
+                mKeyguardStateController.isShowing(),
+                /* showEphemeralMessage= */currentUser.isGuest() && currentUser.isEphemeral(),
+                mFalsingManager,
+                mBroadcastSender,
+                mDialogLaunchAnimator);
         if (dialogShower != null) {
             dialogShower.showDialog(mAddUserDialog,
                     new DialogCuj(
@@ -964,30 +975,6 @@
         return mKeyguardStateController.isShowing();
     }
 
-    @Override
-    @Nullable
-    public EnforcedAdmin getEnforcedAdmin(UserRecord record) {
-        return mEnforcedAdminByUserRecord.get(record);
-    }
-
-    @Override
-    public boolean isDisabledByAdmin(UserRecord record) {
-        return mDisabledByAdmin.contains(record);
-    }
-
-    private void checkIfAddUserDisallowedByAdminOnly(UserRecord record) {
-        EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(mContext,
-                UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId());
-        if (admin != null && !RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
-                UserManager.DISALLOW_ADD_USER, mUserTracker.getUserId())) {
-            mDisabledByAdmin.add(record);
-            mEnforcedAdminByUserRecord.put(record, admin);
-        } else {
-            mDisabledByAdmin.remove(record);
-            mEnforcedAdminByUserRecord.put(record, null);
-        }
-    }
-
     private boolean shouldUseSimpleUserSwitcher() {
         int defaultSimpleUserSwitcher = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_expandLockScreenUserSwitcher) ? 1 : 0;
@@ -1052,133 +1039,4 @@
                     }
                 }
             };
-
-
-    private final class ExitGuestDialog extends SystemUIDialog implements
-            DialogInterface.OnClickListener {
-
-        private final int mGuestId;
-        private final int mTargetId;
-        private final boolean mIsGuestEphemeral;
-
-        ExitGuestDialog(Context context, int guestId, boolean isGuestEphemeral,
-                    int targetId) {
-            super(context);
-            if (isGuestEphemeral) {
-                setTitle(context.getString(
-                            com.android.settingslib.R.string.guest_exit_dialog_title));
-                setMessage(context.getString(
-                            com.android.settingslib.R.string.guest_exit_dialog_message));
-                setButton(DialogInterface.BUTTON_NEUTRAL,
-                        context.getString(android.R.string.cancel), this);
-                setButton(DialogInterface.BUTTON_POSITIVE,
-                        context.getString(
-                            com.android.settingslib.R.string.guest_exit_dialog_button), this);
-            } else {
-                setTitle(context.getString(
-                            com.android.settingslib
-                                .R.string.guest_exit_dialog_title_non_ephemeral));
-                setMessage(context.getString(
-                            com.android.settingslib
-                                .R.string.guest_exit_dialog_message_non_ephemeral));
-                setButton(DialogInterface.BUTTON_NEUTRAL,
-                        context.getString(android.R.string.cancel), this);
-                setButton(DialogInterface.BUTTON_NEGATIVE,
-                        context.getString(
-                            com.android.settingslib.R.string.guest_exit_clear_data_button),
-                        this);
-                setButton(DialogInterface.BUTTON_POSITIVE,
-                        context.getString(
-                            com.android.settingslib.R.string.guest_exit_save_data_button),
-                        this);
-            }
-            SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing());
-            setCanceledOnTouchOutside(false);
-            mGuestId = guestId;
-            mTargetId = targetId;
-            mIsGuestEphemeral = isGuestEphemeral;
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY
-                    : FalsingManager.HIGH_PENALTY;
-            if (mFalsingManager.isFalseTap(penalty)) {
-                return;
-            }
-            if (mIsGuestEphemeral) {
-                if (which == DialogInterface.BUTTON_POSITIVE) {
-                    mDialogLaunchAnimator.dismissStack(this);
-                    // Ephemeral guest: exit guest, guest is removed by the system
-                    // on exit, since its marked ephemeral
-                    exitGuestUser(mGuestId, mTargetId, false);
-                } else if (which == DialogInterface.BUTTON_NEGATIVE) {
-                    // Cancel clicked, do nothing
-                    cancel();
-                }
-            } else {
-                if (which == DialogInterface.BUTTON_POSITIVE) {
-                    mDialogLaunchAnimator.dismissStack(this);
-                    // Non-ephemeral guest: exit guest, guest is not removed by the system
-                    // on exit, since its marked non-ephemeral
-                    exitGuestUser(mGuestId, mTargetId, false);
-                } else if (which == DialogInterface.BUTTON_NEGATIVE) {
-                    mDialogLaunchAnimator.dismissStack(this);
-                    // Non-ephemeral guest: remove guest and then exit
-                    exitGuestUser(mGuestId, mTargetId, true);
-                } else if (which == DialogInterface.BUTTON_NEUTRAL) {
-                    // Cancel clicked, do nothing
-                    cancel();
-                }
-            }
-        }
-    }
-
-    @VisibleForTesting
-    final class AddUserDialog extends SystemUIDialog implements
-            DialogInterface.OnClickListener {
-
-        AddUserDialog(Context context) {
-            super(context);
-
-            setTitle(com.android.settingslib.R.string.user_add_user_title);
-            String message = context.getString(
-                                com.android.settingslib.R.string.user_add_user_message_short);
-            UserInfo currentUser = mUserTracker.getUserInfo();
-            if (currentUser != null && currentUser.isGuest() && currentUser.isEphemeral()) {
-                message += context.getString(R.string.user_add_user_message_guest_remove);
-            }
-            setMessage(message);
-            setButton(DialogInterface.BUTTON_NEUTRAL,
-                    context.getString(android.R.string.cancel), this);
-            setButton(DialogInterface.BUTTON_POSITIVE,
-                    context.getString(android.R.string.ok), this);
-            SystemUIDialog.setWindowOnTop(this, mKeyguardStateController.isShowing());
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            int penalty = which == BUTTON_NEGATIVE ? FalsingManager.NO_PENALTY
-                    : FalsingManager.MODERATE_PENALTY;
-            if (mFalsingManager.isFalseTap(penalty)) {
-                return;
-            }
-            if (which == BUTTON_NEUTRAL) {
-                cancel();
-            } else {
-                mDialogLaunchAnimator.dismissStack(this);
-                if (ActivityManager.isUserAMonkey()) {
-                    return;
-                }
-                // Use broadcast instead of ShadeController, as this dialog may have started in
-                // another process and normal dagger bindings are not available
-                mBroadcastSender.sendBroadcastAsUser(
-                        new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT);
-                getContext().startActivityAsUser(
-                        CreateUserActivity.createIntentForStart(getContext()),
-                        mUserTracker.getUserHandle());
-            }
-        }
-    }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.kt
new file mode 100644
index 0000000..9c38dc0f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepository.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.telephony.data.repository
+
+import android.telephony.Annotation
+import android.telephony.TelephonyCallback
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.telephony.TelephonyListenerManager
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Defines interface for classes that encapsulate _some_ telephony-related state. */
+interface TelephonyRepository {
+    /** The state of the current call. */
+    @Annotation.CallState val callState: Flow<Int>
+}
+
+/**
+ * NOTE: This repository tracks only telephony-related state regarding the default mobile
+ * subscription. `TelephonyListenerManager` does not create new instances of `TelephonyManager` on a
+ * per-subscription basis and thus will always be tracking telephony information regarding
+ * `SubscriptionManager.getDefaultSubscriptionId`. See `TelephonyManager` and `SubscriptionManager`
+ * for more documentation.
+ */
+@SysUISingleton
+class TelephonyRepositoryImpl
+@Inject
+constructor(
+    private val manager: TelephonyListenerManager,
+) : TelephonyRepository {
+    @Annotation.CallState
+    override val callState: Flow<Int> = conflatedCallbackFlow {
+        val listener = TelephonyCallback.CallStateListener { state -> trySend(state) }
+
+        manager.addCallStateListener(listener)
+
+        awaitClose { manager.removeCallStateListener(listener) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryModule.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryModule.kt
index 44c0496..630fbf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryModule.kt
@@ -12,16 +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.statusbar.pipeline.wifi.data.model
+package com.android.systemui.telephony.data.repository
 
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface TelephonyRepositoryModule {
+    @Binds fun repository(impl: TelephonyRepositoryImpl): TelephonyRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt b/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.kt
new file mode 100644
index 0000000..86ca33d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/telephony/domain/interactor/TelephonyInteractor.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.telephony.domain.interactor
+
+import android.telephony.Annotation
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.telephony.data.repository.TelephonyRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** Hosts business logic related to telephony. */
+@SysUISingleton
+class TelephonyInteractor
+@Inject
+constructor(
+    repository: TelephonyRepository,
+) {
+    @Annotation.CallState val callState: Flow<Int> = repository.callState
+}
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index a52e2af..4450b76 100644
--- a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -20,17 +20,19 @@
 import android.annotation.SuppressLint
 import android.content.Context
 import android.graphics.PixelFormat
+import android.graphics.Rect
 import android.graphics.drawable.Drawable
 import android.os.PowerManager
 import android.os.SystemClock
 import android.view.LayoutInflater
+import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
 import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS
 import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS
 import android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT
-import androidx.annotation.CallSuper
+import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -60,7 +62,7 @@
     @LayoutRes private val viewLayoutRes: Int,
     private val windowTitle: String,
     private val wakeReason: String,
-) {
+) : CoreStartable(context) {
     /**
      * Window layout params that will be used as a starting point for the [windowLayoutParams] of
      * all subclasses.
@@ -70,7 +72,8 @@
         width = WindowManager.LayoutParams.WRAP_CONTENT
         height = WindowManager.LayoutParams.WRAP_CONTENT
         type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY
-        flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+        flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+            WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
         title = windowTitle
         format = PixelFormat.TRANSLUCENT
         setTrustedOverlay()
@@ -84,11 +87,8 @@
      */
     internal abstract val windowLayoutParams: WindowManager.LayoutParams
 
-    /** The view currently being displayed. Null if the view is not being displayed. */
-    private var view: ViewGroup? = null
-
-    /** The info currently being displayed. Null if the view is not being displayed. */
-    internal var info: T? = null
+    /** A container for all the display-related objects. Null if the view is not being displayed. */
+    private var displayInfo: DisplayInfo? = null
 
     /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
     private var cancelViewTimeout: Runnable? = null
@@ -100,10 +100,11 @@
      * display the correct information in the view.
      */
     fun displayView(newInfo: T) {
-        val currentView = view
+        val currentDisplayInfo = displayInfo
 
-        if (currentView != null) {
-            updateView(newInfo, currentView)
+        if (currentDisplayInfo != null) {
+            currentDisplayInfo.info = newInfo
+            updateView(currentDisplayInfo.info, currentDisplayInfo.view)
         } else {
             // The view is new, so set up all our callbacks and inflate the view
             configurationController.addCallback(displayScaleListener)
@@ -140,19 +141,24 @@
         val newView = LayoutInflater
                 .from(context)
                 .inflate(viewLayoutRes, null) as ViewGroup
-        view = newView
-        updateView(newInfo, newView)
+        val newViewController = TouchableRegionViewController(newView, this::getTouchableRegion)
+        newViewController.init()
+
+        // We don't need to hold on to the view controller since we never set anything additional
+        // on it -- it will be automatically cleaned up when the view is detached.
+        val newDisplayInfo = DisplayInfo(newView, newInfo)
+        displayInfo = newDisplayInfo
+        updateView(newDisplayInfo.info, newDisplayInfo.view)
         windowManager.addView(newView, windowLayoutParams)
         animateViewIn(newView)
     }
 
     /** Removes then re-inflates the view. */
     private fun reinflateView() {
-        val currentInfo = info
-        if (view == null || currentInfo == null) { return }
+        val currentViewInfo = displayInfo ?: return
 
-        windowManager.removeView(view)
-        inflateAndUpdateView(currentInfo)
+        windowManager.removeView(currentViewInfo.view)
+        inflateAndUpdateView(currentViewInfo.info)
     }
 
     private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
@@ -167,30 +173,67 @@
      * @param removalReason a short string describing why the view was removed (timeout, state
      *     change, etc.)
      */
-    open fun removeView(removalReason: String) {
-        if (view == null) { return }
+    fun removeView(removalReason: String) {
+        val currentDisplayInfo = displayInfo ?: return
+        if (shouldIgnoreViewRemoval(currentDisplayInfo.info, removalReason)) {
+            return
+        }
+
+        val currentView = currentDisplayInfo.view
+        animateViewOut(currentView) { windowManager.removeView(currentView) }
+
         logger.logChipRemoval(removalReason)
         configurationController.removeCallback(displayScaleListener)
-        windowManager.removeView(view)
-        view = null
-        info = null
+        // Re-set to null immediately (instead as part of the animation end runnable) so
+        // that if a new view event comes in while this view is animating out, we still display the
+        // new view appropriately.
+        displayInfo = null
         // No need to time the view out since it's already gone
         cancelViewTimeout?.run()
     }
 
     /**
+     * Returns true if a view removal request should be ignored and false otherwise.
+     *
+     * Allows subclasses to keep the view visible for longer in certain circumstances.
+     */
+    open fun shouldIgnoreViewRemoval(info: T, removalReason: String): Boolean = false
+
+    /**
      * A method implemented by subclasses to update [currentView] based on [newInfo].
      */
-    @CallSuper
-    open fun updateView(newInfo: T, currentView: ViewGroup) {
-        info = newInfo
-    }
+    abstract fun updateView(newInfo: T, currentView: ViewGroup)
+
+    /**
+     * Fills [outRect] with the touchable region of this view. This will be used by WindowManager
+     * to decide which touch events go to the view.
+     */
+    abstract fun getTouchableRegion(view: View, outRect: Rect)
 
     /**
      * A method that can be implemented by subclasses to do custom animations for when the view
      * appears.
      */
-    open fun animateViewIn(view: ViewGroup) {}
+    internal open fun animateViewIn(view: ViewGroup) {}
+
+    /**
+     * A method that can be implemented by subclasses to do custom animations for when the view
+     * disappears.
+     *
+     * @param onAnimationEnd an action that *must* be run once the animation finishes successfully.
+     */
+    internal open fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
+        onAnimationEnd.run()
+    }
+
+    /** A container for all the display-related state objects. */
+    private inner class DisplayInfo(
+        /** The view currently being displayed. */
+        val view: ViewGroup,
+
+        /** The info currently being displayed. */
+        var info: T,
+    )
 }
 
 object TemporaryDisplayRemovalReason {
diff --git a/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
new file mode 100644
index 0000000..60241a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TouchableRegionViewController.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.temporarydisplay
+
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewTreeObserver
+import com.android.systemui.util.ViewController
+
+/**
+ * A view controller that will notify the [ViewTreeObserver] about the touchable region for this
+ * view. This will be used by WindowManager to decide which touch events go to the view and which
+ * pass through to the window below.
+ *
+ * @param touchableRegionSetter a function that, given the view and an out rect, fills the rect with
+ * the touchable region of this view.
+ */
+class TouchableRegionViewController(
+    view: View,
+    touchableRegionSetter: (View, Rect) -> Unit,
+) : ViewController<View>(view) {
+
+    private val tempRect = Rect()
+
+    private val internalInsetsListener =
+        ViewTreeObserver.OnComputeInternalInsetsListener { inoutInfo ->
+            inoutInfo.setTouchableInsets(
+                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
+            )
+
+            tempRect.setEmpty()
+            touchableRegionSetter.invoke(mView, tempRect)
+            inoutInfo.touchableRegion.set(tempRect)
+        }
+
+    public override fun onViewAttached() {
+        mView.viewTreeObserver.addOnComputeInternalInsetsListener(internalInsetsListener)
+    }
+
+    public override fun onViewDetached() {
+        mView.viewTreeObserver.removeOnComputeInternalInsetsListener(internalInsetsListener)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index adef182..a345d99 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -171,6 +171,10 @@
 
         @Override
         public void onColorsChanged(WallpaperColors wallpaperColors, int which, int userId) {
+            WallpaperColors currentColors = mCurrentColors.get(userId);
+            if (wallpaperColors != null && wallpaperColors.equals(currentColors)) {
+                return;
+            }
             boolean currentUser = userId == mUserTracker.getUserId();
             if (currentUser && !mAcceptColorEvents
                     && mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
index 00ed3d6..3ce5ca3 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIModule.java
@@ -22,25 +22,20 @@
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
 import android.os.Handler;
-import android.os.PowerManager;
 
 import androidx.annotation.Nullable;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.keyguard.KeyguardViewController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.ReferenceSystemUIModule;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
 import com.android.systemui.doze.DozeHost;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.gestural.GestureModule;
 import com.android.systemui.plugins.qs.QSFactory;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.dagger.PowerModule;
 import com.android.systemui.privacy.MediaProjectionPrivacyItemMonitor;
 import com.android.systemui.privacy.PrivacyItemMonitor;
@@ -64,8 +59,7 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
+import com.android.systemui.statusbar.policy.AospPolicyModule;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -86,18 +80,21 @@
 import dagger.multibindings.IntoSet;
 
 /**
- * A dagger module for injecting default implementations of components of System UI that may be
- * overridden by the System UI implementation.
+ * A TV specific version of {@link ReferenceSystemUIModule}.
+ *
+ * Code here should be specific to the TV variant of SystemUI and will not be included in other
+ * variants of SystemUI.
  */
-@Module(includes = {
-            GestureModule.class,
-            PowerModule.class,
-            QSModule.class,
-            ReferenceScreenshotModule.class,
-            VolumeModule.class,
-        },
-        subcomponents = {
-        })
+@Module(
+        includes = {
+                AospPolicyModule.class,
+                GestureModule.class,
+                PowerModule.class,
+                QSModule.class,
+                ReferenceScreenshotModule.class,
+                VolumeModule.class,
+        }
+)
 public abstract class TvSystemUIModule {
 
     @SysUISingleton
@@ -114,21 +111,6 @@
 
     @Provides
     @SysUISingleton
-    static BatteryController provideBatteryController(Context context,
-            EnhancedEstimates enhancedEstimates, PowerManager powerManager,
-            BroadcastDispatcher broadcastDispatcher, DemoModeController demoModeController,
-            DumpManager dumpManager,
-            @Main Handler mainHandler, @Background Handler bgHandler) {
-        BatteryController bC = new BatteryControllerImpl(context, enhancedEstimates, powerManager,
-                broadcastDispatcher, demoModeController,
-                dumpManager,
-                mainHandler, bgHandler);
-        bC.init();
-        return bC;
-    }
-
-    @Provides
-    @SysUISingleton
     static SensorPrivacyController provideSensorPrivacyController(
             SensorPrivacyManager sensorPrivacyManager) {
         SensorPrivacyController spC = new SensorPrivacyControllerImpl(sensorPrivacyManager);
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
index 5b522dc..0c72b78 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -20,6 +20,7 @@
 
 import com.android.settingslib.users.EditUserInfoController;
 import com.android.systemui.user.data.repository.UserRepositoryModule;
+import com.android.systemui.user.ui.dialog.UserDialogModule;
 
 import dagger.Binds;
 import dagger.Module;
@@ -32,6 +33,7 @@
  */
 @Module(
         includes = {
+                UserDialogModule.class,
                 UserRepositoryModule.class,
         }
 )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/user/data/model/UserSwitcherSettingsModel.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/user/data/model/UserSwitcherSettingsModel.kt
index 44c0496..4fd55c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/model/UserSwitcherSettingsModel.kt
@@ -12,16 +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.statusbar.pipeline.wifi.data.model
+package com.android.systemui.user.data.model
 
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
+/** Encapsulates the state of settings related to user switching. */
+data class UserSwitcherSettingsModel(
+    val isSimpleUserSwitcher: Boolean = false,
+    val isAddUsersFromLockscreen: Boolean = false,
+    val isUserSwitcherEnabled: Boolean = false,
 )
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
index 0356388..919e699 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -18,9 +18,13 @@
 package com.android.systemui.user.data.repository
 
 import android.content.Context
+import android.content.pm.UserInfo
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.Drawable
+import android.os.UserHandle
 import android.os.UserManager
+import android.provider.Settings
+import androidx.annotation.VisibleForTesting
 import androidx.appcompat.content.res.AppCompatResources
 import com.android.internal.util.UserIcons
 import com.android.systemui.R
@@ -29,15 +33,36 @@
 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.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.user.data.model.UserSwitcherSettingsModel
 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 com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import java.util.concurrent.atomic.AtomicBoolean
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.asExecutor
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 /**
  * Acts as source of truth for user related data.
@@ -55,6 +80,18 @@
     /** List of available user-related actions. */
     val actions: Flow<List<UserActionModel>>
 
+    /** User switcher related settings. */
+    val userSwitcherSettings: Flow<UserSwitcherSettingsModel>
+
+    /** List of all users on the device. */
+    val userInfos: Flow<List<UserInfo>>
+
+    /** [UserInfo] of the currently-selected user. */
+    val selectedUserInfo: Flow<UserInfo>
+
+    /** User ID of the last non-guest selected user. */
+    val lastSelectedNonGuestUserId: Int
+
     /** Whether actions are available even when locked. */
     val isActionableWhenLocked: Flow<Boolean>
 
@@ -62,7 +99,23 @@
     val isGuestUserAutoCreated: Boolean
 
     /** Whether the guest user is currently being reset. */
-    val isGuestUserResetting: Boolean
+    var isGuestUserResetting: Boolean
+
+    /** Whether we've scheduled the creation of a guest user. */
+    val isGuestUserCreationScheduled: AtomicBoolean
+
+    /** The user of the secondary service. */
+    var secondaryUserId: Int
+
+    /** Whether refresh users should be paused. */
+    var isRefreshUsersPaused: Boolean
+
+    /** Asynchronously refresh the list of users. This will cause [userInfos] to be updated. */
+    fun refreshUsers()
+
+    fun getSelectedUserInfo(): UserInfo
+
+    fun isSimpleUserSwitcher(): Boolean
 }
 
 @SysUISingleton
@@ -71,9 +124,31 @@
 constructor(
     @Application private val appContext: Context,
     private val manager: UserManager,
-    controller: UserSwitcherController,
+    private val controller: UserSwitcherController,
+    @Application private val applicationScope: CoroutineScope,
+    @Main private val mainDispatcher: CoroutineDispatcher,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val globalSettings: GlobalSettings,
+    private val tracker: UserTracker,
+    private val featureFlags: FeatureFlags,
 ) : UserRepository {
 
+    private val isNewImpl: Boolean
+        get() = !featureFlags.isEnabled(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER)
+
+    private val _userSwitcherSettings = MutableStateFlow<UserSwitcherSettingsModel?>(null)
+    override val userSwitcherSettings: Flow<UserSwitcherSettingsModel> =
+        _userSwitcherSettings.asStateFlow().filterNotNull()
+
+    private val _userInfos = MutableStateFlow<List<UserInfo>?>(null)
+    override val userInfos: Flow<List<UserInfo>> = _userInfos.filterNotNull()
+
+    private val _selectedUserInfo = MutableStateFlow<UserInfo?>(null)
+    override val selectedUserInfo: Flow<UserInfo> = _selectedUserInfo.filterNotNull()
+
+    override var lastSelectedNonGuestUserId: Int = UserHandle.USER_SYSTEM
+        private set
+
     private val userRecords: Flow<List<UserRecord>> = conflatedCallbackFlow {
         fun send() {
             trySendWithFailureLogging(
@@ -99,11 +174,148 @@
     override val actions: Flow<List<UserActionModel>> =
         userRecords.map { records -> records.filter { it.isNotUser() }.map { it.toActionModel() } }
 
-    override val isActionableWhenLocked: Flow<Boolean> = controller.isAddUsersFromLockScreenEnabled
+    override val isActionableWhenLocked: Flow<Boolean> =
+        if (isNewImpl) {
+            emptyFlow()
+        } else {
+            controller.isAddUsersFromLockScreenEnabled
+        }
 
-    override val isGuestUserAutoCreated: Boolean = controller.isGuestUserAutoCreated
+    override val isGuestUserAutoCreated: Boolean =
+        if (isNewImpl) {
+            appContext.resources.getBoolean(com.android.internal.R.bool.config_guestUserAutoCreated)
+        } else {
+            controller.isGuestUserAutoCreated
+        }
 
-    override val isGuestUserResetting: Boolean = controller.isGuestUserResetting
+    private var _isGuestUserResetting: Boolean = false
+    override var isGuestUserResetting: Boolean =
+        if (isNewImpl) {
+            _isGuestUserResetting
+        } else {
+            controller.isGuestUserResetting
+        }
+        set(value) =
+            if (isNewImpl) {
+                _isGuestUserResetting = value
+            } else {
+                error("Not supported in the old implementation!")
+            }
+
+    override val isGuestUserCreationScheduled = AtomicBoolean()
+
+    override var secondaryUserId: Int = UserHandle.USER_NULL
+
+    override var isRefreshUsersPaused: Boolean = false
+
+    init {
+        if (isNewImpl) {
+            observeSelectedUser()
+            observeUserSettings()
+        }
+    }
+
+    override fun refreshUsers() {
+        applicationScope.launch {
+            val result = withContext(backgroundDispatcher) { manager.aliveUsers }
+
+            if (result != null) {
+                _userInfos.value = result.sortedBy { it.creationTime }
+            }
+        }
+    }
+
+    override fun getSelectedUserInfo(): UserInfo {
+        return checkNotNull(_selectedUserInfo.value)
+    }
+
+    override fun isSimpleUserSwitcher(): Boolean {
+        return checkNotNull(_userSwitcherSettings.value?.isSimpleUserSwitcher)
+    }
+
+    private fun observeSelectedUser() {
+        conflatedCallbackFlow {
+                fun send() {
+                    trySendWithFailureLogging(tracker.userInfo, TAG)
+                }
+
+                val callback =
+                    object : UserTracker.Callback {
+                        override fun onUserChanged(newUser: Int, userContext: Context) {
+                            send()
+                        }
+                    }
+
+                tracker.addCallback(callback, mainDispatcher.asExecutor())
+                send()
+
+                awaitClose { tracker.removeCallback(callback) }
+            }
+            .onEach {
+                if (!it.isGuest) {
+                    lastSelectedNonGuestUserId = it.id
+                }
+
+                _selectedUserInfo.value = it
+            }
+            .launchIn(applicationScope)
+    }
+
+    private fun observeUserSettings() {
+        globalSettings
+            .observerFlow(
+                names =
+                    arrayOf(
+                        SETTING_SIMPLE_USER_SWITCHER,
+                        Settings.Global.ADD_USERS_WHEN_LOCKED,
+                        Settings.Global.USER_SWITCHER_ENABLED,
+                    ),
+                userId = UserHandle.USER_SYSTEM,
+            )
+            .onStart { emit(Unit) } // Forces an initial update.
+            .map { getSettings() }
+            .onEach { _userSwitcherSettings.value = it }
+            .launchIn(applicationScope)
+    }
+
+    private suspend fun getSettings(): UserSwitcherSettingsModel {
+        return withContext(backgroundDispatcher) {
+            val isSimpleUserSwitcher =
+                globalSettings.getIntForUser(
+                    SETTING_SIMPLE_USER_SWITCHER,
+                    if (
+                        appContext.resources.getBoolean(
+                            com.android.internal.R.bool.config_expandLockScreenUserSwitcher
+                        )
+                    ) {
+                        1
+                    } else {
+                        0
+                    },
+                    UserHandle.USER_SYSTEM,
+                ) != 0
+
+            val isAddUsersFromLockscreen =
+                globalSettings.getIntForUser(
+                    Settings.Global.ADD_USERS_WHEN_LOCKED,
+                    0,
+                    UserHandle.USER_SYSTEM,
+                ) != 0
+
+            val isUserSwitcherEnabled =
+                globalSettings.getIntForUser(
+                    Settings.Global.USER_SWITCHER_ENABLED,
+                    0,
+                    UserHandle.USER_SYSTEM,
+                ) != 0
+
+            UserSwitcherSettingsModel(
+                isSimpleUserSwitcher = isSimpleUserSwitcher,
+                isAddUsersFromLockscreen = isAddUsersFromLockscreen,
+                isUserSwitcherEnabled = isUserSwitcherEnabled,
+            )
+        }
+    }
 
     private fun UserRecord.isUser(): Boolean {
         return when {
@@ -125,6 +337,7 @@
             image = getUserImage(this),
             isSelected = isCurrent,
             isSelectable = isSwitchToEnabled || isGuest,
+            isGuest = isGuest,
         )
     }
 
@@ -162,5 +375,6 @@
 
     companion object {
         private const val TAG = "UserRepository"
+        @VisibleForTesting const val SETTING_SIMPLE_USER_SWITCHER = "lockscreenSimpleUserSwitcher"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
index cf6da9a..9370286 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/source/UserRecord.kt
@@ -19,6 +19,7 @@
 import android.content.pm.UserInfo
 import android.graphics.Bitmap
 import android.os.UserHandle
+import com.android.settingslib.RestrictedLockUtils
 
 /** Encapsulates raw data for a user or an option item related to managing users on the device. */
 data class UserRecord(
@@ -41,6 +42,11 @@
     @JvmField val isSwitchToEnabled: Boolean = false,
     /** Whether this record represents an option to add another supervised user to the device. */
     @JvmField val isAddSupervisedUser: Boolean = false,
+    /**
+     * An enforcing admin, if the user action represented by this record is disabled by the admin.
+     * If not disabled, this is `null`.
+     */
+    @JvmField val enforcedAdmin: RestrictedLockUtils.EnforcedAdmin? = null,
 ) {
     /** Returns a new instance of [UserRecord] with its [isCurrent] set to the given value. */
     fun copyWithIsCurrent(isCurrent: Boolean): UserRecord {
@@ -59,6 +65,14 @@
         }
     }
 
+    /**
+     * Returns `true` if the user action represented by this record has been disabled by an admin;
+     * `false` otherwise.
+     */
+    fun isDisabledByAdmin(): Boolean {
+        return enforcedAdmin != null
+    }
+
     companion object {
         @JvmStatic
         fun createForGuest(): UserRecord {
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
new file mode 100644
index 0000000..07e5cf9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/GuestUserInteractor.kt
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.annotation.UserIdInt
+import android.app.admin.DevicePolicyManager
+import android.content.Context
+import android.content.pm.UserInfo
+import android.os.RemoteException
+import android.os.UserHandle
+import android.os.UserManager
+import android.util.Log
+import android.view.WindowManagerGlobal
+import android.widget.Toast
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.QSUserSwitcherEvent
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.domain.model.ShowDialogRequestModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
+
+/** Encapsulates business logic to interact with guest user data and systems. */
+@SysUISingleton
+class GuestUserInteractor
+@Inject
+constructor(
+    @Application private val applicationContext: Context,
+    @Application private val applicationScope: CoroutineScope,
+    @Main private val mainDispatcher: CoroutineDispatcher,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val manager: UserManager,
+    private val repository: UserRepository,
+    private val deviceProvisionedController: DeviceProvisionedController,
+    private val devicePolicyManager: DevicePolicyManager,
+    private val refreshUsersScheduler: RefreshUsersScheduler,
+    private val uiEventLogger: UiEventLogger,
+) {
+    /** 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
+
+    /** Notifies that the device has finished booting. */
+    fun onDeviceBootCompleted() {
+        applicationScope.launch {
+            if (isDeviceAllowedToAddGuest()) {
+                guaranteePresent()
+                return@launch
+            }
+
+            suspendCancellableCoroutine<Unit> { continuation ->
+                val callback =
+                    object : DeviceProvisionedController.DeviceProvisionedListener {
+                        override fun onDeviceProvisionedChanged() {
+                            continuation.resumeWith(Result.success(Unit))
+                            deviceProvisionedController.removeCallback(this)
+                        }
+                    }
+
+                deviceProvisionedController.addCallback(callback)
+            }
+
+            if (isDeviceAllowedToAddGuest()) {
+                guaranteePresent()
+            }
+        }
+    }
+
+    /** Creates a guest user and switches to it. */
+    fun createAndSwitchTo(
+        showDialog: (ShowDialogRequestModel) -> Unit,
+        dismissDialog: () -> Unit,
+        selectUser: (userId: Int) -> Unit,
+    ) {
+        applicationScope.launch {
+            val newGuestUserId = create(showDialog, dismissDialog)
+            if (newGuestUserId != UserHandle.USER_NULL) {
+                selectUser(newGuestUserId)
+            }
+        }
+    }
+
+    /** Exits the guest user, switching back to the last non-guest user or to the default user. */
+    fun exit(
+        @UserIdInt guestUserId: Int,
+        @UserIdInt targetUserId: Int,
+        forceRemoveGuestOnExit: Boolean,
+        showDialog: (ShowDialogRequestModel) -> Unit,
+        dismissDialog: () -> Unit,
+        switchUser: (userId: Int) -> Unit,
+    ) {
+        val currentUserInfo = repository.getSelectedUserInfo()
+        if (currentUserInfo.id != guestUserId) {
+            Log.w(
+                TAG,
+                "User requesting to start a new session ($guestUserId) is not current user" +
+                    " (${currentUserInfo.id})"
+            )
+            return
+        }
+
+        if (!currentUserInfo.isGuest) {
+            Log.w(TAG, "User requesting to start a new session ($guestUserId) is not a guest")
+            return
+        }
+
+        applicationScope.launch {
+            var newUserId = UserHandle.USER_SYSTEM
+            if (targetUserId == UserHandle.USER_NULL) {
+                // When a target user is not specified switch to last non guest user:
+                val lastSelectedNonGuestUserHandle = repository.lastSelectedNonGuestUserId
+                if (lastSelectedNonGuestUserHandle != UserHandle.USER_SYSTEM) {
+                    val info =
+                        withContext(backgroundDispatcher) {
+                            manager.getUserInfo(lastSelectedNonGuestUserHandle)
+                        }
+                    if (info != null && info.isEnabled && info.supportsSwitchToByUser()) {
+                        newUserId = info.id
+                    }
+                }
+            } else {
+                newUserId = targetUserId
+            }
+
+            if (currentUserInfo.isEphemeral || forceRemoveGuestOnExit) {
+                uiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE)
+                remove(currentUserInfo.id, newUserId, showDialog, dismissDialog, switchUser)
+            } else {
+                uiEventLogger.log(QSUserSwitcherEvent.QS_USER_SWITCH)
+                switchUser(newUserId)
+            }
+        }
+    }
+
+    /**
+     * Guarantees that the guest user is present on the device, creating it if needed and if allowed
+     * to.
+     */
+    suspend fun guaranteePresent() {
+        if (!isDeviceAllowedToAddGuest()) {
+            return
+        }
+
+        val guestUser = withContext(backgroundDispatcher) { manager.findCurrentGuestUser() }
+        if (guestUser == null) {
+            scheduleCreation()
+        }
+    }
+
+    /** Removes the guest user from the device. */
+    suspend fun remove(
+        @UserIdInt guestUserId: Int,
+        @UserIdInt targetUserId: Int,
+        showDialog: (ShowDialogRequestModel) -> Unit,
+        dismissDialog: () -> Unit,
+        switchUser: (userId: Int) -> Unit,
+    ) {
+        val currentUser: UserInfo = repository.getSelectedUserInfo()
+        if (currentUser.id != guestUserId) {
+            Log.w(
+                TAG,
+                "User requesting to start a new session ($guestUserId) is not current user" +
+                    " ($currentUser.id)"
+            )
+            return
+        }
+
+        if (!currentUser.isGuest) {
+            Log.w(TAG, "User requesting to start a new session ($guestUserId) is not a guest")
+            return
+        }
+
+        val marked =
+            withContext(backgroundDispatcher) { manager.markGuestForDeletion(currentUser.id) }
+        if (!marked) {
+            Log.w(TAG, "Couldn't mark the guest for deletion for user $guestUserId")
+            return
+        }
+
+        if (targetUserId == UserHandle.USER_NULL) {
+            // Create a new guest in the foreground, and then immediately switch to it
+            val newGuestId = create(showDialog, dismissDialog)
+            if (newGuestId == UserHandle.USER_NULL) {
+                Log.e(TAG, "Could not create new guest, switching back to system user")
+                switchUser(UserHandle.USER_SYSTEM)
+                withContext(backgroundDispatcher) { manager.removeUser(currentUser.id) }
+                try {
+                    WindowManagerGlobal.getWindowManagerService().lockNow(/* options= */ null)
+                } catch (e: RemoteException) {
+                    Log.e(
+                        TAG,
+                        "Couldn't remove guest because ActivityManager or WindowManager is dead"
+                    )
+                }
+                return
+            }
+
+            switchUser(newGuestId)
+
+            withContext(backgroundDispatcher) { manager.removeUser(currentUser.id) }
+        } else {
+            if (repository.isGuestUserAutoCreated) {
+                repository.isGuestUserResetting = true
+            }
+            switchUser(targetUserId)
+            manager.removeUser(currentUser.id)
+        }
+    }
+
+    /**
+     * Creates the guest user and adds it to the device.
+     *
+     * @param showDialog A function to invoke to show a dialog.
+     * @param dismissDialog A function to invoke to dismiss a dialog.
+     * @return The user ID of the newly-created guest user.
+     */
+    private suspend fun create(
+        showDialog: (ShowDialogRequestModel) -> Unit,
+        dismissDialog: () -> Unit,
+    ): Int {
+        return withContext(mainDispatcher) {
+            showDialog(ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true))
+            val guestUserId = createInBackground()
+            dismissDialog()
+            if (guestUserId != UserHandle.USER_NULL) {
+                uiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_ADD)
+            } else {
+                Toast.makeText(
+                        applicationContext,
+                        com.android.settingslib.R.string.add_guest_failed,
+                        Toast.LENGTH_SHORT,
+                    )
+                    .show()
+            }
+
+            guestUserId
+        }
+    }
+
+    /** Schedules the creation of the guest user. */
+    private suspend fun scheduleCreation() {
+        if (!repository.isGuestUserCreationScheduled.compareAndSet(false, true)) {
+            return
+        }
+
+        withContext(backgroundDispatcher) {
+            val newGuestUserId = createInBackground()
+            repository.isGuestUserCreationScheduled.set(false)
+            repository.isGuestUserResetting = false
+            if (newGuestUserId == UserHandle.USER_NULL) {
+                Log.w(TAG, "Could not create new guest while exiting existing guest")
+                // Refresh users so that we still display "Guest" if
+                // config_guestUserAutoCreated=true
+                refreshUsersScheduler.refreshIfNotPaused()
+            }
+        }
+    }
+
+    /**
+     * Creates a guest user and return its multi-user user ID.
+     *
+     * This method does not check if a guest already exists before it makes a call to [UserManager]
+     * to create a new one.
+     *
+     * @return The multi-user user ID of the newly created guest user, or [UserHandle.USER_NULL] if
+     * the guest couldn't be created.
+     */
+    @UserIdInt
+    private suspend fun createInBackground(): Int {
+        return withContext(backgroundDispatcher) {
+            try {
+                val guestUser = manager.createGuest(applicationContext)
+                if (guestUser != null) {
+                    guestUser.id
+                } else {
+                    Log.e(
+                        TAG,
+                        "Couldn't create guest, most likely because there already exists one!"
+                    )
+                    UserHandle.USER_NULL
+                }
+            } catch (e: UserManager.UserOperationException) {
+                Log.e(TAG, "Couldn't create guest user!", e)
+                UserHandle.USER_NULL
+            }
+        }
+    }
+
+    private fun isDeviceAllowedToAddGuest(): Boolean {
+        return deviceProvisionedController.isDeviceProvisioned &&
+            !devicePolicyManager.isDeviceManaged
+    }
+
+    companion object {
+        private const val TAG = "GuestUserInteractor"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/RefreshUsersScheduler.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/RefreshUsersScheduler.kt
new file mode 100644
index 0000000..8f36821
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/RefreshUsersScheduler.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.user.data.repository.UserRepository
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+/** Encapsulates logic for pausing, unpausing, and scheduling a delayed job. */
+@SysUISingleton
+class RefreshUsersScheduler
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    @Main private val mainDispatcher: CoroutineDispatcher,
+    private val repository: UserRepository,
+) {
+    private var scheduledUnpauseJob: Job? = null
+    private var isPaused = false
+
+    fun pause() {
+        applicationScope.launch(mainDispatcher) {
+            isPaused = true
+            scheduledUnpauseJob?.cancel()
+            scheduledUnpauseJob =
+                applicationScope.launch {
+                    delay(PAUSE_REFRESH_USERS_TIMEOUT_MS)
+                    unpauseAndRefresh()
+                }
+        }
+    }
+
+    fun unpauseAndRefresh() {
+        applicationScope.launch(mainDispatcher) {
+            isPaused = false
+            refreshIfNotPaused()
+        }
+    }
+
+    fun refreshIfNotPaused() {
+        applicationScope.launch(mainDispatcher) {
+            if (isPaused) {
+                return@launch
+            }
+
+            repository.refreshUsers()
+        }
+    }
+
+    companion object {
+        private const val PAUSE_REFRESH_USERS_TIMEOUT_MS = 3000L
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
new file mode 100644
index 0000000..1b4746a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserActionsUtil.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.os.UserHandle
+import android.os.UserManager
+import com.android.systemui.user.data.repository.UserRepository
+
+/** Utilities related to user management actions. */
+object UserActionsUtil {
+
+    /** Returns `true` if it's possible to add a guest user to the device; `false` otherwise. */
+    fun canCreateGuest(
+        manager: UserManager,
+        repository: UserRepository,
+        isUserSwitcherEnabled: Boolean,
+        isAddUsersFromLockScreenEnabled: Boolean,
+    ): Boolean {
+        if (!isUserSwitcherEnabled) {
+            return false
+        }
+
+        return currentUserCanCreateUsers(manager, repository) ||
+            anyoneCanCreateUsers(manager, isAddUsersFromLockScreenEnabled)
+    }
+
+    /** Returns `true` if it's possible to add a user to the device; `false` otherwise. */
+    fun canCreateUser(
+        manager: UserManager,
+        repository: UserRepository,
+        isUserSwitcherEnabled: Boolean,
+        isAddUsersFromLockScreenEnabled: Boolean,
+    ): Boolean {
+        if (!isUserSwitcherEnabled) {
+            return false
+        }
+
+        if (
+            !currentUserCanCreateUsers(manager, repository) &&
+                !anyoneCanCreateUsers(manager, isAddUsersFromLockScreenEnabled)
+        ) {
+            return false
+        }
+
+        return manager.canAddMoreUsers(UserManager.USER_TYPE_FULL_SECONDARY)
+    }
+
+    /**
+     * Returns `true` if it's possible to add a supervised user to the device; `false` otherwise.
+     */
+    fun canCreateSupervisedUser(
+        manager: UserManager,
+        repository: UserRepository,
+        isUserSwitcherEnabled: Boolean,
+        isAddUsersFromLockScreenEnabled: Boolean,
+        supervisedUserPackageName: String?
+    ): Boolean {
+        if (supervisedUserPackageName.isNullOrEmpty()) {
+            return false
+        }
+
+        return canCreateUser(
+            manager,
+            repository,
+            isUserSwitcherEnabled,
+            isAddUsersFromLockScreenEnabled
+        )
+    }
+
+    /**
+     * Returns `true` if the current user is allowed to add users to the device; `false` otherwise.
+     */
+    private fun currentUserCanCreateUsers(
+        manager: UserManager,
+        repository: UserRepository,
+    ): Boolean {
+        val currentUser = repository.getSelectedUserInfo()
+        if (!currentUser.isAdmin && currentUser.id != UserHandle.USER_SYSTEM) {
+            return false
+        }
+
+        return systemCanCreateUsers(manager)
+    }
+
+    /** Returns `true` if the system can add users to the device; `false` otherwise. */
+    private fun systemCanCreateUsers(
+        manager: UserManager,
+    ): Boolean {
+        return !manager.hasBaseUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.SYSTEM)
+    }
+
+    /** Returns `true` if it's allowed to add users to the device at all; `false` otherwise. */
+    private fun anyoneCanCreateUsers(
+        manager: UserManager,
+        isAddUsersFromLockScreenEnabled: Boolean,
+    ): Boolean {
+        return systemCanCreateUsers(manager) && isAddUsersFromLockScreenEnabled
+    }
+}
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
index 3c5b969..142a328 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -17,94 +17,747 @@
 
 package com.android.systemui.user.domain.interactor
 
+import android.annotation.SuppressLint
+import android.annotation.UserIdInt
+import android.app.ActivityManager
+import android.content.Context
 import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.UserInfo
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.os.RemoteException
+import android.os.UserHandle
+import android.os.UserManager
 import android.provider.Settings
+import android.util.Log
+import com.android.internal.util.UserIcons
+import com.android.systemui.R
+import com.android.systemui.SystemUISecondaryUserService
+import com.android.systemui.broadcast.BroadcastDispatcher
+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.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.user.UserSwitchDialogController
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
 import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.domain.model.ShowDialogRequestModel
+import com.android.systemui.user.legacyhelper.data.LegacyUserDataHelper
 import com.android.systemui.user.shared.model.UserActionModel
 import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.util.kotlin.pairwise
+import java.io.PrintWriter
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
 
 /** Encapsulates business logic to interact with user data and systems. */
 @SysUISingleton
 class UserInteractor
 @Inject
 constructor(
-    repository: UserRepository,
+    @Application private val applicationContext: Context,
+    private val repository: UserRepository,
     private val controller: UserSwitcherController,
     private val activityStarter: ActivityStarter,
-    keyguardInteractor: KeyguardInteractor,
+    private val keyguardInteractor: KeyguardInteractor,
+    private val featureFlags: FeatureFlags,
+    private val manager: UserManager,
+    @Application private val applicationScope: CoroutineScope,
+    telephonyInteractor: TelephonyInteractor,
+    broadcastDispatcher: BroadcastDispatcher,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val activityManager: ActivityManager,
+    private val refreshUsersScheduler: RefreshUsersScheduler,
+    private val guestUserInteractor: GuestUserInteractor,
 ) {
+    /**
+     * Defines interface for classes that can be notified when the state of users on the device is
+     * changed.
+     */
+    interface UserCallback {
+        /** Returns `true` if this callback can be cleaned-up. */
+        fun isEvictable(): Boolean = false
+        /** Notifies that the state of users on the device has changed. */
+        fun onUserStateChanged()
+    }
+
+    private val isNewImpl: Boolean
+        get() = !featureFlags.isEnabled(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER)
+
+    private val supervisedUserPackageName: String?
+        get() =
+            applicationContext.getString(
+                com.android.internal.R.string.config_supervisedUserCreationPackage
+            )
+
+    private val callbackMutex = Mutex()
+    private val callbacks = mutableSetOf<UserCallback>()
+
     /** List of current on-device users to select from. */
-    val users: Flow<List<UserModel>> = repository.users
+    val users: Flow<List<UserModel>>
+        get() =
+            if (isNewImpl) {
+                combine(
+                    repository.userInfos,
+                    repository.selectedUserInfo,
+                    repository.userSwitcherSettings,
+                ) { userInfos, selectedUserInfo, settings ->
+                    toUserModels(
+                        userInfos = userInfos,
+                        selectedUserId = selectedUserInfo.id,
+                        isUserSwitcherEnabled = settings.isUserSwitcherEnabled,
+                    )
+                }
+            } else {
+                repository.users
+            }
 
     /** The currently-selected user. */
-    val selectedUser: Flow<UserModel> = repository.selectedUser
+    val selectedUser: Flow<UserModel>
+        get() =
+            if (isNewImpl) {
+                combine(
+                    repository.selectedUserInfo,
+                    repository.userSwitcherSettings,
+                ) { selectedUserInfo, settings ->
+                    val selectedUserId = selectedUserInfo.id
+                    checkNotNull(
+                        toUserModel(
+                            userInfo = selectedUserInfo,
+                            selectedUserId = selectedUserId,
+                            canSwitchUsers = canSwitchUsers(selectedUserId),
+                            isUserSwitcherEnabled = settings.isUserSwitcherEnabled,
+                        )
+                    )
+                }
+            } else {
+                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()
-                            }
+    val actions: Flow<List<UserActionModel>>
+        get() =
+            if (isNewImpl) {
+                combine(
+                    repository.userInfos,
+                    repository.userSwitcherSettings,
+                    keyguardInteractor.isKeyguardShowing,
+                ) { userInfos, settings, isDeviceLocked ->
+                    buildList {
+                        val hasGuestUser = userInfos.any { it.isGuest }
+                        if (
+                            !hasGuestUser &&
+                                (guestUserInteractor.isGuestUserAutoCreated ||
+                                    UserActionsUtil.canCreateGuest(
+                                        manager,
+                                        repository,
+                                        settings.isUserSwitcherEnabled,
+                                        settings.isAddUsersFromLockscreen,
+                                    ))
+                        ) {
+                            add(UserActionModel.ENTER_GUEST_MODE)
+                        }
+
+                        if (isDeviceLocked && !settings.isAddUsersFromLockscreen) {
+                            // The device is locked and our setting to allow actions that add users
+                            // from the lock-screen is not enabled. The guest action from above is
+                            // always allowed, even when the device is locked, but the various "add
+                            // user" actions below are not. We can finish building the list here.
+                            return@buildList
+                        }
+
+                        if (
+                            UserActionsUtil.canCreateUser(
+                                manager,
+                                repository,
+                                settings.isUserSwitcherEnabled,
+                                settings.isAddUsersFromLockscreen,
+                            )
+                        ) {
+                            add(UserActionModel.ADD_USER)
+                        }
+
+                        if (
+                            UserActionsUtil.canCreateSupervisedUser(
+                                manager,
+                                repository,
+                                settings.isUserSwitcherEnabled,
+                                settings.isAddUsersFromLockscreen,
+                                supervisedUserPackageName,
+                            )
+                        ) {
+                            add(UserActionModel.ADD_SUPERVISED_USER)
+                        }
                     }
-                } 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())
                 }
+            } else {
+                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())
+                        }
+                    }
             }
 
+    val userRecords: StateFlow<ArrayList<UserRecord>> =
+        if (isNewImpl) {
+            combine(
+                    repository.userInfos,
+                    repository.selectedUserInfo,
+                    actions,
+                    repository.userSwitcherSettings,
+                ) { userInfos, selectedUserInfo, actionModels, settings ->
+                    ArrayList(
+                        userInfos.map {
+                            toRecord(
+                                userInfo = it,
+                                selectedUserId = selectedUserInfo.id,
+                            )
+                        } +
+                            actionModels.map {
+                                toRecord(
+                                    action = it,
+                                    selectedUserId = selectedUserInfo.id,
+                                    isAddFromLockscreenEnabled = settings.isAddUsersFromLockscreen,
+                                )
+                            }
+                    )
+                }
+                .onEach { notifyCallbacks() }
+                .stateIn(
+                    scope = applicationScope,
+                    started = SharingStarted.Eagerly,
+                    initialValue = ArrayList(),
+                )
+        } else {
+            MutableStateFlow(ArrayList())
+        }
+
+    val selectedUserRecord: StateFlow<UserRecord?> =
+        if (isNewImpl) {
+            repository.selectedUserInfo
+                .map { selectedUserInfo ->
+                    toRecord(userInfo = selectedUserInfo, selectedUserId = selectedUserInfo.id)
+                }
+                .stateIn(
+                    scope = applicationScope,
+                    started = SharingStarted.Eagerly,
+                    initialValue = null,
+                )
+        } else {
+            MutableStateFlow(null)
+        }
+
     /** Whether the device is configured to always have a guest user available. */
-    val isGuestUserAutoCreated: Boolean = repository.isGuestUserAutoCreated
+    val isGuestUserAutoCreated: Boolean = guestUserInteractor.isGuestUserAutoCreated
 
     /** Whether the guest user is currently being reset. */
-    val isGuestUserResetting: Boolean = repository.isGuestUserResetting
+    val isGuestUserResetting: Boolean = guestUserInteractor.isGuestUserResetting
+
+    private val _dialogShowRequests = MutableStateFlow<ShowDialogRequestModel?>(null)
+    val dialogShowRequests: Flow<ShowDialogRequestModel?> = _dialogShowRequests.asStateFlow()
+
+    private val _dialogDismissRequests = MutableStateFlow<Unit?>(null)
+    val dialogDismissRequests: Flow<Unit?> = _dialogDismissRequests.asStateFlow()
+
+    val isSimpleUserSwitcher: Boolean
+        get() =
+            if (isNewImpl) {
+                repository.isSimpleUserSwitcher()
+            } else {
+                error("Not supported in the old implementation!")
+            }
+
+    init {
+        if (isNewImpl) {
+            refreshUsersScheduler.refreshIfNotPaused()
+            telephonyInteractor.callState
+                .distinctUntilChanged()
+                .onEach { refreshUsersScheduler.refreshIfNotPaused() }
+                .launchIn(applicationScope)
+
+            combine(
+                    broadcastDispatcher.broadcastFlow(
+                        filter =
+                            IntentFilter().apply {
+                                addAction(Intent.ACTION_USER_ADDED)
+                                addAction(Intent.ACTION_USER_REMOVED)
+                                addAction(Intent.ACTION_USER_INFO_CHANGED)
+                                addAction(Intent.ACTION_USER_SWITCHED)
+                                addAction(Intent.ACTION_USER_STOPPED)
+                                addAction(Intent.ACTION_USER_UNLOCKED)
+                            },
+                        user = UserHandle.SYSTEM,
+                        map = { intent, _ -> intent },
+                    ),
+                    repository.selectedUserInfo.pairwise(null),
+                ) { intent, selectedUserChange ->
+                    Pair(intent, selectedUserChange.previousValue)
+                }
+                .onEach { (intent, previousSelectedUser) ->
+                    onBroadcastReceived(intent, previousSelectedUser)
+                }
+                .launchIn(applicationScope)
+        }
+    }
+
+    fun addCallback(callback: UserCallback) {
+        applicationScope.launch { callbackMutex.withLock { callbacks.add(callback) } }
+    }
+
+    fun removeCallback(callback: UserCallback) {
+        applicationScope.launch { callbackMutex.withLock { callbacks.remove(callback) } }
+    }
+
+    fun refreshUsers() {
+        refreshUsersScheduler.refreshIfNotPaused()
+    }
+
+    fun onDialogShown() {
+        _dialogShowRequests.value = null
+    }
+
+    fun onDialogDismissed() {
+        _dialogDismissRequests.value = null
+    }
+
+    fun dump(pw: PrintWriter) {
+        pw.println("UserInteractor state:")
+        pw.println("  lastSelectedNonGuestUserId=${repository.lastSelectedNonGuestUserId}")
+
+        val users = userRecords.value.filter { it.info != null }
+        pw.println("  userCount=${userRecords.value.count { LegacyUserDataHelper.isUser(it) }}")
+        for (i in users.indices) {
+            pw.println("    ${users[i]}")
+        }
+
+        val actions = userRecords.value.filter { it.info == null }
+        pw.println("  actionCount=${userRecords.value.count { !LegacyUserDataHelper.isUser(it) }}")
+        for (i in actions.indices) {
+            pw.println("    ${actions[i]}")
+        }
+
+        pw.println("isSimpleUserSwitcher=$isSimpleUserSwitcher")
+        pw.println("isGuestUserAutoCreated=$isGuestUserAutoCreated")
+    }
+
+    fun onDeviceBootCompleted() {
+        guestUserInteractor.onDeviceBootCompleted()
+    }
+
+    /** Switches to the user or executes the action represented by the given record. */
+    fun onRecordSelected(
+        record: UserRecord,
+        dialogShower: UserSwitchDialogController.DialogShower? = null,
+    ) {
+        if (LegacyUserDataHelper.isUser(record)) {
+            // It's safe to use checkNotNull around record.info because isUser only returns true
+            // if record.info is not null.
+            selectUser(checkNotNull(record.info).id, dialogShower)
+        } else {
+            executeAction(LegacyUserDataHelper.toUserActionModel(record), dialogShower)
+        }
+    }
 
     /** Switches to the user with the given user ID. */
     fun selectUser(
-        userId: Int,
+        newlySelectedUserId: Int,
+        dialogShower: UserSwitchDialogController.DialogShower? = null,
     ) {
-        controller.onUserSelected(userId, /* dialogShower= */ null)
+        if (isNewImpl) {
+            val currentlySelectedUserInfo = repository.getSelectedUserInfo()
+            if (
+                newlySelectedUserId == currentlySelectedUserInfo.id &&
+                    currentlySelectedUserInfo.isGuest
+            ) {
+                // Here when clicking on the currently-selected guest user to leave guest mode
+                // and return to the previously-selected non-guest user.
+                showDialog(
+                    ShowDialogRequestModel.ShowExitGuestDialog(
+                        guestUserId = currentlySelectedUserInfo.id,
+                        targetUserId = repository.lastSelectedNonGuestUserId,
+                        isGuestEphemeral = currentlySelectedUserInfo.isEphemeral,
+                        isKeyguardShowing = keyguardInteractor.isKeyguardShowing(),
+                        onExitGuestUser = this::exitGuestUser,
+                    )
+                )
+                return
+            }
+
+            if (currentlySelectedUserInfo.isGuest) {
+                // Here when switching from guest to a non-guest user.
+                showDialog(
+                    ShowDialogRequestModel.ShowExitGuestDialog(
+                        guestUserId = currentlySelectedUserInfo.id,
+                        targetUserId = newlySelectedUserId,
+                        isGuestEphemeral = currentlySelectedUserInfo.isEphemeral,
+                        isKeyguardShowing = keyguardInteractor.isKeyguardShowing(),
+                        onExitGuestUser = this::exitGuestUser,
+                    )
+                )
+                return
+            }
+
+            dialogShower?.dismiss()
+
+            switchUser(newlySelectedUserId)
+        } else {
+            controller.onUserSelected(newlySelectedUserId, dialogShower)
+        }
     }
 
     /** 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,
-                )
+    fun executeAction(
+        action: UserActionModel,
+        dialogShower: UserSwitchDialogController.DialogShower? = null,
+    ) {
+        if (isNewImpl) {
+            when (action) {
+                UserActionModel.ENTER_GUEST_MODE ->
+                    guestUserInteractor.createAndSwitchTo(
+                        this::showDialog,
+                        this::dismissDialog,
+                    ) { userId ->
+                        selectUser(userId, dialogShower)
+                    }
+                UserActionModel.ADD_USER -> {
+                    val currentUser = repository.getSelectedUserInfo()
+                    showDialog(
+                        ShowDialogRequestModel.ShowAddUserDialog(
+                            userHandle = currentUser.userHandle,
+                            isKeyguardShowing = keyguardInteractor.isKeyguardShowing(),
+                            showEphemeralMessage = currentUser.isGuest && currentUser.isEphemeral,
+                        )
+                    )
+                }
+                UserActionModel.ADD_SUPERVISED_USER ->
+                    activityStarter.startActivity(
+                        Intent()
+                            .setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
+                            .setPackage(supervisedUserPackageName)
+                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
+                        /* dismissShade= */ false,
+                    )
+                UserActionModel.NAVIGATE_TO_USER_MANAGEMENT ->
+                    activityStarter.startActivity(
+                        Intent(Settings.ACTION_USER_SETTINGS),
+                        /* dismissShade= */ false,
+                    )
+            }
+        } else {
+            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,
+                    )
+            }
         }
     }
+
+    fun exitGuestUser(
+        @UserIdInt guestUserId: Int,
+        @UserIdInt targetUserId: Int,
+        forceRemoveGuestOnExit: Boolean,
+    ) {
+        guestUserInteractor.exit(
+            guestUserId = guestUserId,
+            targetUserId = targetUserId,
+            forceRemoveGuestOnExit = forceRemoveGuestOnExit,
+            showDialog = this::showDialog,
+            dismissDialog = this::dismissDialog,
+            switchUser = this::switchUser,
+        )
+    }
+
+    fun removeGuestUser(
+        @UserIdInt guestUserId: Int,
+        @UserIdInt targetUserId: Int,
+    ) {
+        applicationScope.launch {
+            guestUserInteractor.remove(
+                guestUserId = guestUserId,
+                targetUserId = targetUserId,
+                ::showDialog,
+                ::dismissDialog,
+                ::selectUser,
+            )
+        }
+    }
+
+    private fun showDialog(request: ShowDialogRequestModel) {
+        _dialogShowRequests.value = request
+    }
+
+    private fun dismissDialog() {
+        _dialogDismissRequests.value = Unit
+    }
+
+    private fun notifyCallbacks() {
+        applicationScope.launch {
+            callbackMutex.withLock {
+                val iterator = callbacks.iterator()
+                while (iterator.hasNext()) {
+                    val callback = iterator.next()
+                    if (!callback.isEvictable()) {
+                        callback.onUserStateChanged()
+                    } else {
+                        iterator.remove()
+                    }
+                }
+            }
+        }
+    }
+
+    private suspend fun toRecord(
+        userInfo: UserInfo,
+        selectedUserId: Int,
+    ): UserRecord {
+        return LegacyUserDataHelper.createRecord(
+            context = applicationContext,
+            manager = manager,
+            userInfo = userInfo,
+            picture = null,
+            isCurrent = userInfo.id == selectedUserId,
+            canSwitchUsers = canSwitchUsers(selectedUserId),
+        )
+    }
+
+    private suspend fun toRecord(
+        action: UserActionModel,
+        selectedUserId: Int,
+        isAddFromLockscreenEnabled: Boolean,
+    ): UserRecord {
+        return LegacyUserDataHelper.createRecord(
+            context = applicationContext,
+            selectedUserId = selectedUserId,
+            actionType = action,
+            isRestricted =
+                if (action == UserActionModel.ENTER_GUEST_MODE) {
+                    // Entering guest mode is never restricted, so it's allowed to happen from the
+                    // lockscreen even if the "add from lockscreen" system setting is off.
+                    false
+                } else {
+                    !isAddFromLockscreenEnabled
+                },
+            isSwitchToEnabled =
+                canSwitchUsers(selectedUserId) &&
+                    // If the user is auto-created is must not be currently resetting.
+                    !(isGuestUserAutoCreated && isGuestUserResetting),
+        )
+    }
+
+    private fun switchUser(userId: Int) {
+        // TODO(b/246631653): track jank and latency like in the old impl.
+        refreshUsersScheduler.pause()
+        try {
+            activityManager.switchUser(userId)
+        } catch (e: RemoteException) {
+            Log.e(TAG, "Couldn't switch user.", e)
+        }
+    }
+
+    private suspend fun onBroadcastReceived(
+        intent: Intent,
+        previousUserInfo: UserInfo?,
+    ) {
+        val shouldRefreshAllUsers =
+            when (intent.action) {
+                Intent.ACTION_USER_SWITCHED -> {
+                    dismissDialog()
+                    val selectedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
+                    if (previousUserInfo?.id != selectedUserId) {
+                        notifyCallbacks()
+                        restartSecondaryService(selectedUserId)
+                    }
+                    if (guestUserInteractor.isGuestUserAutoCreated) {
+                        guestUserInteractor.guaranteePresent()
+                    }
+                    true
+                }
+                Intent.ACTION_USER_INFO_CHANGED -> true
+                Intent.ACTION_USER_UNLOCKED -> {
+                    // If we unlocked the system user, we should refresh all users.
+                    intent.getIntExtra(
+                        Intent.EXTRA_USER_HANDLE,
+                        UserHandle.USER_NULL,
+                    ) == UserHandle.USER_SYSTEM
+                }
+                else -> true
+            }
+
+        if (shouldRefreshAllUsers) {
+            refreshUsersScheduler.unpauseAndRefresh()
+        }
+    }
+
+    private fun restartSecondaryService(@UserIdInt userId: Int) {
+        val intent = Intent(applicationContext, SystemUISecondaryUserService::class.java)
+        // Disconnect from the old secondary user's service
+        val secondaryUserId = repository.secondaryUserId
+        if (secondaryUserId != UserHandle.USER_NULL) {
+            applicationContext.stopServiceAsUser(
+                intent,
+                UserHandle.of(secondaryUserId),
+            )
+            repository.secondaryUserId = UserHandle.USER_NULL
+        }
+
+        // Connect to the new secondary user's service (purely to ensure that a persistent
+        // SystemUI application is created for that user)
+        if (userId != UserHandle.USER_SYSTEM) {
+            applicationContext.startServiceAsUser(
+                intent,
+                UserHandle.of(userId),
+            )
+            repository.secondaryUserId = userId
+        }
+    }
+
+    private suspend fun toUserModels(
+        userInfos: List<UserInfo>,
+        selectedUserId: Int,
+        isUserSwitcherEnabled: Boolean,
+    ): List<UserModel> {
+        val canSwitchUsers = canSwitchUsers(selectedUserId)
+
+        return userInfos
+            // The guest user should go in the last position.
+            .sortedBy { it.isGuest }
+            .mapNotNull { userInfo ->
+                toUserModel(
+                    userInfo = userInfo,
+                    selectedUserId = selectedUserId,
+                    canSwitchUsers = canSwitchUsers,
+                    isUserSwitcherEnabled = isUserSwitcherEnabled,
+                )
+            }
+    }
+
+    private suspend fun toUserModel(
+        userInfo: UserInfo,
+        selectedUserId: Int,
+        canSwitchUsers: Boolean,
+        isUserSwitcherEnabled: Boolean,
+    ): UserModel? {
+        val userId = userInfo.id
+        val isSelected = userId == selectedUserId
+
+        return when {
+            // When the user switcher is not enabled in settings, we only show the primary user.
+            !isUserSwitcherEnabled && !userInfo.isPrimary -> null
+
+            // We avoid showing disabled users.
+            !userInfo.isEnabled -> null
+            userInfo.isGuest ->
+                UserModel(
+                    id = userId,
+                    name = Text.Loaded(userInfo.name),
+                    image =
+                        getUserImage(
+                            isGuest = true,
+                            userId = userId,
+                        ),
+                    isSelected = isSelected,
+                    isSelectable = canSwitchUsers,
+                    isGuest = true,
+                )
+            userInfo.supportsSwitchToByUser() ->
+                UserModel(
+                    id = userId,
+                    name = Text.Loaded(userInfo.name),
+                    image =
+                        getUserImage(
+                            isGuest = false,
+                            userId = userId,
+                        ),
+                    isSelected = isSelected,
+                    isSelectable = canSwitchUsers || isSelected,
+                    isGuest = false,
+                )
+            else -> null
+        }
+    }
+
+    private suspend fun canSwitchUsers(selectedUserId: Int): Boolean {
+        return withContext(backgroundDispatcher) {
+            manager.getUserSwitchability(UserHandle.of(selectedUserId))
+        } == UserManager.SWITCHABILITY_STATUS_OK
+    }
+
+    @SuppressLint("UseCompatLoadingForDrawables")
+    private suspend fun getUserImage(
+        isGuest: Boolean,
+        userId: Int,
+    ): Drawable {
+        if (isGuest) {
+            return checkNotNull(applicationContext.getDrawable(R.drawable.ic_account_circle))
+        }
+
+        // TODO(b/246631653): cache the bitmaps to avoid the background work to fetch them.
+        // TODO(b/246631653): downscale the bitmaps to R.dimen.max_avatar_size if requested.
+        val userIcon = withContext(backgroundDispatcher) { manager.getUserIcon(userId) }
+        if (userIcon != null) {
+            return BitmapDrawable(userIcon)
+        }
+
+        return UserIcons.getDefaultUserIcon(
+            applicationContext.resources,
+            userId,
+            /* light= */ false
+        )
+    }
+
+    companion object {
+        private const val TAG = "UserInteractor"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt
new file mode 100644
index 0000000..08d7c5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.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.systemui.user.domain.model
+
+import android.os.UserHandle
+
+/** Encapsulates a request to show a dialog. */
+sealed class ShowDialogRequestModel {
+    data class ShowAddUserDialog(
+        val userHandle: UserHandle,
+        val isKeyguardShowing: Boolean,
+        val showEphemeralMessage: Boolean,
+    ) : ShowDialogRequestModel()
+
+    data class ShowUserCreationDialog(
+        val isGuest: Boolean,
+    ) : ShowDialogRequestModel()
+
+    data class ShowExitGuestDialog(
+        val guestUserId: Int,
+        val targetUserId: Int,
+        val isGuestEphemeral: Boolean,
+        val isKeyguardShowing: Boolean,
+        val onExitGuestUser: (guestId: Int, targetId: Int, forceRemoveGuest: Boolean) -> Unit,
+    ) : ShowDialogRequestModel()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
new file mode 100644
index 0000000..137de15
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/legacyhelper/data/LegacyUserDataHelper.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.data
+
+import android.content.Context
+import android.content.pm.UserInfo
+import android.graphics.Bitmap
+import android.os.UserManager
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
+import com.android.settingslib.RestrictedLockUtilsInternal
+import com.android.systemui.R
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.shared.model.UserActionModel
+
+/**
+ * Defines utility functions for helping with legacy data 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 LegacyUserDataHelper {
+
+    @JvmStatic
+    fun createRecord(
+        context: Context,
+        manager: UserManager,
+        picture: Bitmap?,
+        userInfo: UserInfo,
+        isCurrent: Boolean,
+        canSwitchUsers: Boolean,
+    ): UserRecord {
+        val isGuest = userInfo.isGuest
+        return UserRecord(
+            info = userInfo,
+            picture =
+                getPicture(
+                    manager = manager,
+                    context = context,
+                    userInfo = userInfo,
+                    picture = picture,
+                ),
+            isGuest = isGuest,
+            isCurrent = isCurrent,
+            isSwitchToEnabled = canSwitchUsers || (isCurrent && !isGuest),
+        )
+    }
+
+    @JvmStatic
+    fun createRecord(
+        context: Context,
+        selectedUserId: Int,
+        actionType: UserActionModel,
+        isRestricted: Boolean,
+        isSwitchToEnabled: Boolean,
+    ): UserRecord {
+        return UserRecord(
+            isGuest = actionType == UserActionModel.ENTER_GUEST_MODE,
+            isAddUser = actionType == UserActionModel.ADD_USER,
+            isAddSupervisedUser = actionType == UserActionModel.ADD_SUPERVISED_USER,
+            isRestricted = isRestricted,
+            isSwitchToEnabled = isSwitchToEnabled,
+            enforcedAdmin =
+                getEnforcedAdmin(
+                    context = context,
+                    selectedUserId = selectedUserId,
+                ),
+        )
+    }
+
+    fun toUserActionModel(record: UserRecord): UserActionModel {
+        check(!isUser(record))
+
+        return when {
+            record.isAddUser -> UserActionModel.ADD_USER
+            record.isAddSupervisedUser -> UserActionModel.ADD_SUPERVISED_USER
+            record.isGuest -> UserActionModel.ENTER_GUEST_MODE
+            else -> error("Not a known action: $record")
+        }
+    }
+
+    fun isUser(record: UserRecord): Boolean {
+        return record.info != null
+    }
+
+    private fun getEnforcedAdmin(
+        context: Context,
+        selectedUserId: Int,
+    ): EnforcedAdmin? {
+        val admin =
+            RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
+                context,
+                UserManager.DISALLOW_ADD_USER,
+                selectedUserId,
+            )
+                ?: return null
+
+        return if (
+            !RestrictedLockUtilsInternal.hasBaseUserRestriction(
+                context,
+                UserManager.DISALLOW_ADD_USER,
+                selectedUserId,
+            )
+        ) {
+            admin
+        } else {
+            null
+        }
+    }
+
+    private fun getPicture(
+        context: Context,
+        manager: UserManager,
+        userInfo: UserInfo,
+        picture: Bitmap?,
+    ): Bitmap? {
+        if (userInfo.isGuest) {
+            return null
+        }
+
+        if (picture != null) {
+            return picture
+        }
+
+        val unscaledOrNull = manager.getUserIcon(userInfo.id) ?: return null
+
+        val avatarSize = context.resources.getDimensionPixelSize(R.dimen.max_avatar_size)
+        return Bitmap.createScaledBitmap(
+            unscaledOrNull,
+            avatarSize,
+            avatarSize,
+            /* filter= */ true,
+        )
+    }
+}
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
index bf7977a..2095683 100644
--- a/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/shared/model/UserModel.kt
@@ -32,4 +32,6 @@
     val isSelected: Boolean,
     /** Whether this use is selectable. A non-selectable user cannot be switched to. */
     val isSelectable: Boolean,
+    /** Whether this model represents the guest user. */
+    val isGuest: Boolean,
 )
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt
new file mode 100644
index 0000000..a9d66de
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/AddUserDialog.kt
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.dialog
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.DialogInterface
+import android.content.Intent
+import android.os.UserHandle
+import com.android.settingslib.R
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.user.CreateUserActivity
+
+/** Dialog for adding a new user to the device. */
+class AddUserDialog(
+    context: Context,
+    userHandle: UserHandle,
+    isKeyguardShowing: Boolean,
+    showEphemeralMessage: Boolean,
+    private val falsingManager: FalsingManager,
+    private val broadcastSender: BroadcastSender,
+    private val dialogLaunchAnimator: DialogLaunchAnimator
+) : SystemUIDialog(context) {
+
+    private val onClickListener =
+        object : DialogInterface.OnClickListener {
+            override fun onClick(dialog: DialogInterface, which: Int) {
+                val penalty =
+                    if (which == BUTTON_NEGATIVE) {
+                        FalsingManager.NO_PENALTY
+                    } else {
+                        FalsingManager.MODERATE_PENALTY
+                    }
+                if (falsingManager.isFalseTap(penalty)) {
+                    return
+                }
+
+                if (which == BUTTON_NEUTRAL) {
+                    cancel()
+                    return
+                }
+
+                dialogLaunchAnimator.dismissStack(this@AddUserDialog)
+                if (ActivityManager.isUserAMonkey()) {
+                    return
+                }
+
+                // Use broadcast instead of ShadeController, as this dialog may have started in
+                // another
+                // process where normal dagger bindings are not available.
+                broadcastSender.sendBroadcastAsUser(
+                    Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
+                    UserHandle.CURRENT
+                )
+
+                context.startActivityAsUser(
+                    CreateUserActivity.createIntentForStart(context),
+                    userHandle,
+                )
+            }
+        }
+
+    init {
+        setTitle(R.string.user_add_user_title)
+        val message =
+            context.getString(R.string.user_add_user_message_short) +
+                if (showEphemeralMessage) {
+                    context.getString(
+                        com.android.systemui.R.string.user_add_user_message_guest_remove
+                    )
+                } else {
+                    ""
+                }
+        setMessage(message)
+
+        setButton(
+            BUTTON_NEUTRAL,
+            context.getString(android.R.string.cancel),
+            onClickListener,
+        )
+
+        setButton(
+            BUTTON_POSITIVE,
+            context.getString(android.R.string.ok),
+            onClickListener,
+        )
+
+        setWindowOnTop(this, isKeyguardShowing)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/ExitGuestDialog.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/ExitGuestDialog.kt
new file mode 100644
index 0000000..19ad44d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/ExitGuestDialog.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.dialog
+
+import android.annotation.UserIdInt
+import android.content.Context
+import android.content.DialogInterface
+import com.android.settingslib.R
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.statusbar.phone.SystemUIDialog
+
+/** Dialog for exiting the guest user. */
+class ExitGuestDialog(
+    context: Context,
+    private val guestUserId: Int,
+    private val isGuestEphemeral: Boolean,
+    private val targetUserId: Int,
+    isKeyguardShowing: Boolean,
+    private val falsingManager: FalsingManager,
+    private val dialogLaunchAnimator: DialogLaunchAnimator,
+    private val onExitGuestUserListener: OnExitGuestUserListener,
+) : SystemUIDialog(context) {
+
+    fun interface OnExitGuestUserListener {
+        fun onExitGuestUser(
+            @UserIdInt guestId: Int,
+            @UserIdInt targetId: Int,
+            forceRemoveGuest: Boolean,
+        )
+    }
+
+    private val onClickListener =
+        object : DialogInterface.OnClickListener {
+            override fun onClick(dialog: DialogInterface, which: Int) {
+                val penalty =
+                    if (which == BUTTON_NEGATIVE) {
+                        FalsingManager.NO_PENALTY
+                    } else {
+                        FalsingManager.MODERATE_PENALTY
+                    }
+                if (falsingManager.isFalseTap(penalty)) {
+                    return
+                }
+
+                if (isGuestEphemeral) {
+                    if (which == BUTTON_POSITIVE) {
+                        dialogLaunchAnimator.dismissStack(this@ExitGuestDialog)
+                        // Ephemeral guest: exit guest, guest is removed by the system
+                        // on exit, since its marked ephemeral
+                        onExitGuestUserListener.onExitGuestUser(guestUserId, targetUserId, false)
+                    } else if (which == BUTTON_NEGATIVE) {
+                        // Cancel clicked, do nothing
+                        cancel()
+                    }
+                } else {
+                    when (which) {
+                        BUTTON_POSITIVE -> {
+                            dialogLaunchAnimator.dismissStack(this@ExitGuestDialog)
+                            // Non-ephemeral guest: exit guest, guest is not removed by the system
+                            // on exit, since its marked non-ephemeral
+                            onExitGuestUserListener.onExitGuestUser(
+                                guestUserId,
+                                targetUserId,
+                                false
+                            )
+                        }
+                        BUTTON_NEGATIVE -> {
+                            dialogLaunchAnimator.dismissStack(this@ExitGuestDialog)
+                            // Non-ephemeral guest: remove guest and then exit
+                            onExitGuestUserListener.onExitGuestUser(guestUserId, targetUserId, true)
+                        }
+                        BUTTON_NEUTRAL -> {
+                            // Cancel clicked, do nothing
+                            cancel()
+                        }
+                    }
+                }
+            }
+        }
+
+    init {
+        if (isGuestEphemeral) {
+            setTitle(context.getString(R.string.guest_exit_dialog_title))
+            setMessage(context.getString(R.string.guest_exit_dialog_message))
+            setButton(
+                BUTTON_NEUTRAL,
+                context.getString(android.R.string.cancel),
+                onClickListener,
+            )
+            setButton(
+                BUTTON_POSITIVE,
+                context.getString(R.string.guest_exit_dialog_button),
+                onClickListener,
+            )
+        } else {
+            setTitle(context.getString(R.string.guest_exit_dialog_title_non_ephemeral))
+            setMessage(context.getString(R.string.guest_exit_dialog_message_non_ephemeral))
+            setButton(
+                BUTTON_NEUTRAL,
+                context.getString(android.R.string.cancel),
+                onClickListener,
+            )
+            setButton(
+                BUTTON_NEGATIVE,
+                context.getString(R.string.guest_exit_clear_data_button),
+                onClickListener,
+            )
+            setButton(
+                BUTTON_POSITIVE,
+                context.getString(R.string.guest_exit_save_data_button),
+                onClickListener,
+            )
+        }
+        setWindowOnTop(this, isKeyguardShowing)
+        setCanceledOnTouchOutside(false)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserDialogModule.kt
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserDialogModule.kt
index 44c0496..c1d2f47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserDialogModule.kt
@@ -12,16 +12,22 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF 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.wifi.data.model
+package com.android.systemui.user.ui.dialog
 
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+import com.android.systemui.CoreStartable
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+
+@Module
+interface UserDialogModule {
+
+    @Binds
+    @IntoMap
+    @ClassKey(UserSwitcherDialogCoordinator::class)
+    fun bindFeature(impl: UserSwitcherDialogCoordinator): CoreStartable
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt
new file mode 100644
index 0000000..6e7b523
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.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.user.ui.dialog
+
+import android.app.Dialog
+import android.content.Context
+import com.android.settingslib.users.UserCreatingDialog
+import com.android.systemui.CoreStartable
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.domain.model.ShowDialogRequestModel
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.filterNotNull
+import kotlinx.coroutines.launch
+
+/** Coordinates dialogs for user switcher logic. */
+@SysUISingleton
+class UserSwitcherDialogCoordinator
+@Inject
+constructor(
+    @Application private val context: Context,
+    @Application private val applicationScope: CoroutineScope,
+    private val falsingManager: FalsingManager,
+    private val broadcastSender: BroadcastSender,
+    private val dialogLaunchAnimator: DialogLaunchAnimator,
+    private val interactor: UserInteractor,
+    private val featureFlags: FeatureFlags,
+) : CoreStartable(context) {
+
+    private var currentDialog: Dialog? = null
+
+    override fun start() {
+        if (featureFlags.isEnabled(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER)) {
+            return
+        }
+
+        startHandlingDialogShowRequests()
+        startHandlingDialogDismissRequests()
+    }
+
+    private fun startHandlingDialogShowRequests() {
+        applicationScope.launch {
+            interactor.dialogShowRequests.filterNotNull().collect { request ->
+                currentDialog?.let {
+                    if (it.isShowing) {
+                        it.cancel()
+                    }
+                }
+
+                currentDialog =
+                    when (request) {
+                        is ShowDialogRequestModel.ShowAddUserDialog ->
+                            AddUserDialog(
+                                context = context,
+                                userHandle = request.userHandle,
+                                isKeyguardShowing = request.isKeyguardShowing,
+                                showEphemeralMessage = request.showEphemeralMessage,
+                                falsingManager = falsingManager,
+                                broadcastSender = broadcastSender,
+                                dialogLaunchAnimator = dialogLaunchAnimator,
+                            )
+                        is ShowDialogRequestModel.ShowUserCreationDialog ->
+                            UserCreatingDialog(
+                                context,
+                                request.isGuest,
+                            )
+                        is ShowDialogRequestModel.ShowExitGuestDialog ->
+                            ExitGuestDialog(
+                                context = context,
+                                guestUserId = request.guestUserId,
+                                isGuestEphemeral = request.isGuestEphemeral,
+                                targetUserId = request.targetUserId,
+                                isKeyguardShowing = request.isKeyguardShowing,
+                                falsingManager = falsingManager,
+                                dialogLaunchAnimator = dialogLaunchAnimator,
+                                onExitGuestUserListener = request.onExitGuestUser,
+                            )
+                    }
+
+                currentDialog?.show()
+                interactor.onDialogShown()
+            }
+        }
+    }
+
+    private fun startHandlingDialogDismissRequests() {
+        applicationScope.launch {
+            interactor.dialogDismissRequests.filterNotNull().collect {
+                currentDialog?.let {
+                    if (it.isShowing) {
+                        it.cancel()
+                    }
+                }
+
+                interactor.onDialogDismissed()
+            }
+        }
+    }
+}
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
index 398341d..5b83df7 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -21,7 +21,10 @@
 import androidx.lifecycle.ViewModelProvider
 import com.android.systemui.R
 import com.android.systemui.common.ui.drawable.CircularDrawable
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.domain.interactor.GuestUserInteractor
 import com.android.systemui.user.domain.interactor.UserInteractor
 import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
 import com.android.systemui.user.shared.model.UserActionModel
@@ -36,9 +39,14 @@
 class UserSwitcherViewModel
 private constructor(
     private val userInteractor: UserInteractor,
+    private val guestUserInteractor: GuestUserInteractor,
     private val powerInteractor: PowerInteractor,
+    private val featureFlags: FeatureFlags,
 ) : ViewModel() {
 
+    private val isNewImpl: Boolean
+        get() = !featureFlags.isEnabled(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER)
+
     /** On-device users. */
     val users: Flow<List<UserViewModel>> =
         userInteractor.users.map { models -> models.map { user -> toViewModel(user) } }
@@ -47,9 +55,6 @@
     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
@@ -58,9 +63,23 @@
     val isMenuVisible: Flow<Boolean> = _isMenuVisible
     /** The user action menu. */
     val menu: Flow<List<UserActionViewModel>> =
-        userInteractor.actions.map { actions -> actions.map { action -> toViewModel(action) } }
+        userInteractor.actions.map { actions ->
+            if (isNewImpl && 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.
+                    actions + listOf(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
+                } else {
+                    actions
+                }
+                .map { action -> toViewModel(action) }
+        }
+
+    /** Whether the button to open the user action menu is visible. */
+    val isOpenMenuButtonVisible: Flow<Boolean> = menu.map { it.isNotEmpty() }
 
     private val hasCancelButtonBeenClicked = MutableStateFlow(false)
+    private val isFinishRequiredDueToExecutedAction = MutableStateFlow(false)
 
     /**
      * Whether the observer should finish the experience. Once consumed, [onFinished] must be called
@@ -81,6 +100,7 @@
      */
     fun onFinished() {
         hasCancelButtonBeenClicked.value = false
+        isFinishRequiredDueToExecutedAction.value = false
     }
 
     /** Notifies that the user has clicked the "open menu" button. */
@@ -120,8 +140,10 @@
             },
             // When the cancel button is clicked, we should finish.
             hasCancelButtonBeenClicked,
-        ) { selectedUserChanged, screenTurnedOff, cancelButtonClicked ->
-            selectedUserChanged || screenTurnedOff || cancelButtonClicked
+            // If an executed action told us to finish, we should finish,
+            isFinishRequiredDueToExecutedAction,
+        ) { selectedUserChanged, screenTurnedOff, cancelButtonClicked, executedActionFinish ->
+            selectedUserChanged || screenTurnedOff || cancelButtonClicked || executedActionFinish
         }
     }
 
@@ -164,13 +186,25 @@
                 } else {
                     LegacyUserUiHelper.getUserSwitcherActionTextResourceId(
                         isGuest = model == UserActionModel.ENTER_GUEST_MODE,
-                        isGuestUserAutoCreated = userInteractor.isGuestUserAutoCreated,
-                        isGuestUserResetting = userInteractor.isGuestUserResetting,
+                        isGuestUserAutoCreated = guestUserInteractor.isGuestUserAutoCreated,
+                        isGuestUserResetting = guestUserInteractor.isGuestUserResetting,
                         isAddSupervisedUser = model == UserActionModel.ADD_SUPERVISED_USER,
                         isAddUser = model == UserActionModel.ADD_USER,
                     )
                 },
-            onClicked = { userInteractor.executeAction(action = model) },
+            onClicked = {
+                userInteractor.executeAction(action = model)
+                // We don't finish because we want to show a dialog over the full-screen UI and
+                // that dialog can be dismissed in case the user changes their mind and decides not
+                // to add a user.
+                //
+                // We finish for all other actions because they navigate us away from the
+                // full-screen experience or are destructive (like changing to the guest user).
+                val shouldFinish = model != UserActionModel.ADD_USER
+                if (shouldFinish) {
+                    isFinishRequiredDueToExecutedAction.value = true
+                }
+            },
         )
     }
 
@@ -186,13 +220,17 @@
     @Inject
     constructor(
         private val userInteractor: UserInteractor,
+        private val guestUserInteractor: GuestUserInteractor,
         private val powerInteractor: PowerInteractor,
+        private val featureFlags: FeatureFlags,
     ) : ViewModelProvider.Factory {
         override fun <T : ViewModel> create(modelClass: Class<T>): T {
             @Suppress("UNCHECKED_CAST")
             return UserSwitcherViewModel(
                 userInteractor = userInteractor,
+                guestUserInteractor = guestUserInteractor,
                 powerInteractor = powerInteractor,
+                featureFlags = featureFlags,
             )
                 as T
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java b/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
index 5f7d745..a925e38 100644
--- a/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/util/CarrierConfigTracker.java
@@ -67,6 +67,8 @@
     private boolean mDefaultCarrierProvisionsWifiMergedNetworks;
     private boolean mDefaultShowOperatorNameConfigLoaded;
     private boolean mDefaultShowOperatorNameConfig;
+    private boolean mDefaultAlwaysShowPrimarySignalBarInOpportunisticNetworkConfigLoaded;
+    private boolean mDefaultAlwaysShowPrimarySignalBarInOpportunisticNetworkConfig;
 
     @Inject
     public CarrierConfigTracker(
@@ -207,6 +209,22 @@
     }
 
     /**
+     * Returns KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN value for
+     * the default carrier config.
+     */
+    public boolean getAlwaysShowPrimarySignalBarInOpportunisticNetworkDefault() {
+        if (!mDefaultAlwaysShowPrimarySignalBarInOpportunisticNetworkConfigLoaded) {
+            mDefaultAlwaysShowPrimarySignalBarInOpportunisticNetworkConfig = CarrierConfigManager
+                    .getDefaultConfig().getBoolean(CarrierConfigManager
+                            .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN
+                    );
+            mDefaultAlwaysShowPrimarySignalBarInOpportunisticNetworkConfigLoaded = true;
+        }
+
+        return mDefaultAlwaysShowPrimarySignalBarInOpportunisticNetworkConfig;
+    }
+
+    /**
      * Returns the KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL value for the given subId, or the
      * default value if no override exists
      *
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 8c736dc..81ae6e8 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -25,6 +25,7 @@
 
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.BroadcastRunning;
 import com.android.systemui.dagger.qualifiers.LongRunning;
 import com.android.systemui.dagger.qualifiers.Main;
 
@@ -51,6 +52,17 @@
         return thread.getLooper();
     }
 
+    /** BroadcastRunning Looper (for sending and receiving broadcasts) */
+    @Provides
+    @SysUISingleton
+    @BroadcastRunning
+    public static Looper provideBroadcastRunningLooper() {
+        HandlerThread thread = new HandlerThread("BroadcastRunning",
+                Process.THREAD_PRIORITY_BACKGROUND);
+        thread.start();
+        return thread.getLooper();
+    }
+
     /** Long running tasks Looper */
     @Provides
     @SysUISingleton
@@ -83,7 +95,17 @@
     }
 
     /**
-     * Provide a Long running Executor by default.
+     * Provide a BroadcastRunning Executor (for sending and receiving broadcasts).
+     */
+    @Provides
+    @SysUISingleton
+    @BroadcastRunning
+    public static Executor provideBroadcastRunningExecutor(@BroadcastRunning Looper looper) {
+        return new ExecutorImpl(looper);
+    }
+
+    /**
+     * Provide a Long running Executor.
      */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java b/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java
index db35437e..ecb365f 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java
@@ -34,9 +34,26 @@
     private final String mTag = getClass().getSimpleName();
 
     private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
-    private boolean mIsConditionMet = false;
+    private final boolean mOverriding;
+    private Boolean mIsConditionMet;
     private boolean mStarted = false;
-    private boolean mOverriding = false;
+
+    /**
+     * By default, conditions have an initial value of false and are not overriding.
+     */
+    public Condition() {
+        this(false, false);
+    }
+
+    /**
+     * Constructor for specifying initial state and overriding condition attribute.
+     * @param initialConditionMet Initial state of the condition.
+     * @param overriding Whether this condition overrides others.
+     */
+    protected Condition(Boolean initialConditionMet, boolean overriding) {
+        mIsConditionMet = initialConditionMet;
+        mOverriding = overriding;
+    }
 
     /**
      * Starts monitoring the condition.
@@ -49,14 +66,6 @@
     protected abstract void stop();
 
     /**
-     * Sets whether this condition's value overrides others in determining the overall state.
-     */
-    public void setOverriding(boolean overriding) {
-        mOverriding = overriding;
-        updateCondition(mIsConditionMet);
-    }
-
-    /**
      * Returns whether the current condition overrides
      */
     public boolean isOverridingCondition() {
@@ -110,13 +119,31 @@
      * @param isConditionMet True if the condition has been fulfilled. False otherwise.
      */
     protected void updateCondition(boolean isConditionMet) {
-        if (mIsConditionMet == isConditionMet) {
+        if (mIsConditionMet != null && mIsConditionMet == isConditionMet) {
             return;
         }
 
         if (shouldLog()) Log.d(mTag, "updating condition to " + isConditionMet);
         mIsConditionMet = isConditionMet;
+        sendUpdate();
+    }
 
+    /**
+     * Clears the set condition value. This is purposefully separate from
+     * {@link #updateCondition(boolean)} to avoid confusion around {@code null} values.
+     */
+    protected void clearCondition() {
+        if (mIsConditionMet == null) {
+            return;
+        }
+
+        if (shouldLog()) Log.d(mTag, "clearing condition");
+
+        mIsConditionMet = null;
+        sendUpdate();
+    }
+
+    private void sendUpdate() {
         final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
         while (iterator.hasNext()) {
             final Callback cb = iterator.next().get();
@@ -128,8 +155,21 @@
         }
     }
 
+    /**
+     * Returns whether the condition is set. This method should be consulted to understand the
+     * value of {@link #isConditionMet()}.
+     * @return {@code true} if value is present, {@code false} otherwise.
+     */
+    public boolean isConditionSet() {
+        return mIsConditionMet != null;
+    }
+
+    /**
+     * Returns whether the condition has been met. Note that this method will return {@code false}
+     * if the condition is not set as well.
+     */
     public boolean isConditionMet() {
-        return mIsConditionMet;
+        return Boolean.TRUE.equals(mIsConditionMet);
     }
 
     private boolean shouldLog() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
index dac8a0b..4824f67 100644
--- a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java
@@ -57,12 +57,16 @@
         }
 
         public void update() {
+            // Only consider set conditions.
+            final Collection<Condition> setConditions = mSubscription.mConditions.stream()
+                    .filter(Condition::isConditionSet).collect(Collectors.toSet());
+
             // Overriding conditions do not override each other
-            final Collection<Condition> overridingConditions = mSubscription.mConditions.stream()
+            final Collection<Condition> overridingConditions = setConditions.stream()
                     .filter(Condition::isOverridingCondition).collect(Collectors.toSet());
 
             final Collection<Condition> targetCollection = overridingConditions.isEmpty()
-                    ? mSubscription.mConditions : overridingConditions;
+                    ? setConditions : overridingConditions;
 
             final boolean newAllConditionsMet = targetCollection.isEmpty() ? true : targetCollection
                     .stream()
diff --git a/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
new file mode 100644
index 0000000..0b8257d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/settings/SettingsProxyExt.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.settings
+
+import android.annotation.UserIdInt
+import android.database.ContentObserver
+import android.os.UserHandle
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/** Kotlin extension functions for [SettingsProxy]. */
+object SettingsProxyExt {
+
+    /** Returns a flow of [Unit] that is invoked each time that content is updated. */
+    fun SettingsProxy.observerFlow(
+        vararg names: String,
+        @UserIdInt userId: Int = UserHandle.USER_CURRENT,
+    ): Flow<Unit> {
+        return conflatedCallbackFlow {
+            val observer =
+                object : ContentObserver(null) {
+                    override fun onChange(selfChange: Boolean) {
+                        trySend(Unit)
+                    }
+                }
+
+            names.forEach { name -> registerContentObserverForUser(name, observer, userId) }
+
+            awaitClose { unregisterContentObserver(observer) }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
index 613a797..6160b00 100644
--- a/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/view/ViewUtil.kt
@@ -1,5 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.view
 
+import android.graphics.Rect
 import android.view.View
 import com.android.systemui.dagger.SysUISingleton
 import javax.inject.Inject
@@ -23,4 +40,22 @@
                 top <= y &&
                 y <= top + view.height
     }
+
+    /**
+     * Sets [outRect] to be the view's location within its window.
+     */
+    fun setRectToViewWindowLocation(view: View, outRect: Rect) {
+        val locInWindow = IntArray(2)
+        view.getLocationInWindow(locInWindow)
+
+        val x = locInWindow[0]
+        val y = locInWindow[1]
+
+        outRect.set(
+            x,
+            y,
+            x + view.width,
+            y + view.height,
+        )
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index bf7c459..7c022eb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -65,6 +65,7 @@
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.qs.tiles.DndTile;
@@ -178,7 +179,8 @@
             WakefulnessLifecycle wakefulnessLifecycle,
             CaptioningManager captioningManager,
             KeyguardManager keyguardManager,
-            ActivityManager activityManager
+            ActivityManager activityManager,
+            DumpManager dumpManager
     ) {
         mContext = context.getApplicationContext();
         mPackageManager = packageManager;
@@ -207,7 +209,7 @@
         mCaptioningManager = captioningManager;
         mKeyguardManager = keyguardManager;
         mActivityManager = activityManager;
-
+        dumpManager.registerDumpable("VolumeDialogControllerImpl", this);
 
         boolean accessibilityVolumeStreamActive = accessibilityManager
                 .isAccessibilityVolumeStreamActive();
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index 0f7e143..42d7d52 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -16,21 +16,17 @@
 
 package com.android.systemui.wallpapers;
 
-import static android.view.Display.DEFAULT_DISPLAY;
-
 import static com.android.systemui.flags.Flags.USE_CANVAS_RENDERER;
 
 import android.app.WallpaperColors;
 import android.app.WallpaperManager;
-import android.content.ComponentCallbacks2;
-import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
-import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.SystemClock;
@@ -40,8 +36,6 @@
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Size;
-import android.view.Display;
-import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 import android.view.WindowManager;
@@ -49,8 +43,11 @@
 import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.wallpapers.canvas.ImageCanvasWallpaperRenderer;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.wallpapers.canvas.WallpaperColorExtractor;
 import com.android.systemui.wallpapers.gl.EglHelper;
 import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
 
@@ -59,6 +56,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -78,15 +76,28 @@
     private final ArrayList<RectF> mLocalColorsToAdd = new ArrayList<>();
     private final ArraySet<RectF> mColorAreas = new ArraySet<>();
     private volatile int mPages = 1;
+    private boolean mPagesComputed = false;
     private HandlerThread mWorker;
     // scaled down version
     private Bitmap mMiniBitmap;
     private final FeatureFlags mFeatureFlags;
 
+    // used in canvasEngine to load/unload the bitmap and extract the colors
+    @Background
+    private final DelayableExecutor mBackgroundExecutor;
+    private static final int DELAY_UNLOAD_BITMAP = 2000;
+
+    @Main
+    private final Executor mMainExecutor;
+
     @Inject
-    public ImageWallpaper(FeatureFlags featureFlags) {
+    public ImageWallpaper(FeatureFlags featureFlags,
+            @Background DelayableExecutor backgroundExecutor,
+            @Main Executor mainExecutor) {
         super();
         mFeatureFlags = featureFlags;
+        mBackgroundExecutor = backgroundExecutor;
+        mMainExecutor = mainExecutor;
     }
 
     @Override
@@ -339,7 +350,6 @@
                 imgArea.left = 0;
                 imgArea.right = 1;
             }
-
             return imgArea;
         }
 
@@ -510,69 +520,85 @@
 
 
     class CanvasEngine extends WallpaperService.Engine implements DisplayListener {
-
-        // time [ms] before unloading the wallpaper after it is loaded
-        private static final int DELAY_FORGET_WALLPAPER = 5000;
-
-        private final Runnable mUnloadWallpaperCallback = this::unloadWallpaper;
-
         private WallpaperManager mWallpaperManager;
-        private ImageCanvasWallpaperRenderer mImageCanvasWallpaperRenderer;
+        private final WallpaperColorExtractor mWallpaperColorExtractor;
+        private SurfaceHolder mSurfaceHolder;
+        @VisibleForTesting
+        static final int MIN_SURFACE_WIDTH = 128;
+        @VisibleForTesting
+        static final int MIN_SURFACE_HEIGHT = 128;
         private Bitmap mBitmap;
+        private boolean mWideColorGamut = false;
 
-        private Display mDisplay;
-        private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
-
-        private AsyncTask<Void, Void, Bitmap> mLoader;
-        private boolean mNeedsDrawAfterLoadingWallpaper = false;
+        /*
+         * Counter to unload the bitmap as soon as possible.
+         * Before any bitmap operation, this is incremented.
+         * After an operation completion, this is decremented (synchronously),
+         * and if the count is 0, unload the bitmap
+         */
+        private int mBitmapUsages = 0;
+        private final Object mLock = new Object();
 
         CanvasEngine() {
             super();
             setFixedSizeAllowed(true);
             setShowForAllUsers(true);
-        }
+            mWallpaperColorExtractor = new WallpaperColorExtractor(
+                    mBackgroundExecutor,
+                    new WallpaperColorExtractor.WallpaperColorExtractorCallback() {
+                        @Override
+                        public void onColorsProcessed(List<RectF> regions,
+                                List<WallpaperColors> colors) {
+                            CanvasEngine.this.onColorsProcessed(regions, colors);
+                        }
 
-        void trimMemory(int level) {
-            if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW
-                    && level <= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL
-                    && isBitmapLoaded()) {
-                if (DEBUG) {
-                    Log.d(TAG, "trimMemory");
-                }
-                unloadWallpaper();
+                        @Override
+                        public void onMiniBitmapUpdated() {
+                            CanvasEngine.this.onMiniBitmapUpdated();
+                        }
+
+                        @Override
+                        public void onActivated() {
+                            setOffsetNotificationsEnabled(true);
+                        }
+
+                        @Override
+                        public void onDeactivated() {
+                            setOffsetNotificationsEnabled(false);
+                        }
+                    });
+
+            // if the number of pages is already computed, transmit it to the color extractor
+            if (mPagesComputed) {
+                mWallpaperColorExtractor.onPageChanged(mPages);
             }
         }
 
         @Override
         public void onCreate(SurfaceHolder surfaceHolder) {
+            Trace.beginSection("ImageWallpaper.CanvasEngine#onCreate");
             if (DEBUG) {
                 Log.d(TAG, "onCreate");
             }
+            mWallpaperManager = getDisplayContext().getSystemService(WallpaperManager.class);
+            mSurfaceHolder = surfaceHolder;
+            Rect dimensions = mWallpaperManager.peekBitmapDimensions();
+            int width = Math.max(MIN_SURFACE_WIDTH, dimensions.width());
+            int height = Math.max(MIN_SURFACE_HEIGHT, dimensions.height());
+            mSurfaceHolder.setFixedSize(width, height);
 
-            mWallpaperManager = getSystemService(WallpaperManager.class);
-            super.onCreate(surfaceHolder);
-
-            final Context displayContext = getDisplayContext();
-            final int displayId = displayContext == null ? DEFAULT_DISPLAY :
-                    displayContext.getDisplayId();
-            DisplayManager dm = getSystemService(DisplayManager.class);
-            if (dm != null) {
-                mDisplay = dm.getDisplay(displayId);
-                if (mDisplay == null) {
-                    Log.e(TAG, "Cannot find display! Fallback to default.");
-                    mDisplay = dm.getDisplay(DEFAULT_DISPLAY);
-                }
-            }
-            setOffsetNotificationsEnabled(false);
-
-            mImageCanvasWallpaperRenderer = new ImageCanvasWallpaperRenderer(surfaceHolder);
-            loadWallpaper(false);
+            getDisplayContext().getSystemService(DisplayManager.class)
+                    .registerDisplayListener(this, null);
+            getDisplaySizeAndUpdateColorExtractor();
+            Trace.endSection();
         }
 
         @Override
         public void onDestroy() {
-            super.onDestroy();
-            unloadWallpaper();
+            getDisplayContext().getSystemService(DisplayManager.class)
+                    .unregisterDisplayListener(this);
+            mWallpaperColorExtractor.cleanUp();
+            unloadBitmap();
         }
 
         @Override
@@ -581,31 +607,30 @@
         }
 
         @Override
+        public boolean shouldWaitForEngineShown() {
+            return true;
+        }
+
+        @Override
         public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
             if (DEBUG) {
                 Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height);
             }
-            super.onSurfaceChanged(holder, format, width, height);
-            mImageCanvasWallpaperRenderer.setSurfaceHolder(holder);
-            drawFrame(false);
         }
 
         @Override
         public void onSurfaceDestroyed(SurfaceHolder holder) {
-            super.onSurfaceDestroyed(holder);
             if (DEBUG) {
                 Log.i(TAG, "onSurfaceDestroyed");
             }
-            mImageCanvasWallpaperRenderer.setSurfaceHolder(null);
+            mSurfaceHolder = null;
         }
 
         @Override
         public void onSurfaceCreated(SurfaceHolder holder) {
-            super.onSurfaceCreated(holder);
             if (DEBUG) {
                 Log.i(TAG, "onSurfaceCreated");
             }
-            mImageCanvasWallpaperRenderer.setSurfaceHolder(holder);
         }
 
         @Override
@@ -613,135 +638,90 @@
             if (DEBUG) {
                 Log.d(TAG, "onSurfaceRedrawNeeded");
             }
-            super.onSurfaceRedrawNeeded(holder);
-            // At the end of this method we should have drawn into the surface.
-            // This means that the bitmap should be loaded synchronously if
-            // it was already unloaded.
-            if (!isBitmapLoaded()) {
-                setBitmap(mWallpaperManager.getBitmap(true /* hardware */));
+            drawFrame();
+        }
+
+        private void drawFrame() {
+            mBackgroundExecutor.execute(this::drawFrameSynchronized);
+        }
+
+        private void drawFrameSynchronized() {
+            synchronized (mLock) {
+                drawFrameInternal();
             }
-            drawFrame(true);
         }
 
-        private DisplayInfo getDisplayInfo() {
-            mDisplay.getDisplayInfo(mTmpDisplayInfo);
-            return mTmpDisplayInfo;
-        }
-
-        private void drawFrame(boolean forceRedraw) {
-            if (!mImageCanvasWallpaperRenderer.isSurfaceHolderLoaded()) {
+        private void drawFrameInternal() {
+            if (mSurfaceHolder == null) {
                 Log.e(TAG, "attempt to draw a frame without a valid surface");
                 return;
             }
 
+            // load the wallpaper if not already done
             if (!isBitmapLoaded()) {
-                // ensure that we load the wallpaper.
-                // if the wallpaper is currently loading, this call will have no effect.
-                loadWallpaper(true);
-                return;
-            }
-            mImageCanvasWallpaperRenderer.drawFrame(mBitmap, forceRedraw);
-        }
-
-        private void setBitmap(Bitmap bitmap) {
-            if (bitmap == null) {
-                Log.e(TAG, "Attempt to set a null bitmap");
-            } else if (mBitmap == bitmap) {
-                Log.e(TAG, "The value of bitmap is the same");
-            } else if (bitmap.getWidth() < 1 || bitmap.getHeight() < 1) {
-                Log.e(TAG, "Attempt to set an invalid wallpaper of length "
-                        + bitmap.getWidth() + "x" + bitmap.getHeight());
+                loadWallpaperAndDrawFrameInternal();
             } else {
-                if (mBitmap != null) {
-                    mBitmap.recycle();
-                }
-                mBitmap = bitmap;
+                mBitmapUsages++;
+
+                // drawing is done on the main thread
+                mMainExecutor.execute(() -> {
+                    drawFrameOnCanvas(mBitmap);
+                    reportEngineShown(false);
+                    unloadBitmapIfNotUsed();
+                });
             }
         }
 
-        private boolean isBitmapLoaded() {
+        @VisibleForTesting
+        void drawFrameOnCanvas(Bitmap bitmap) {
+            Trace.beginSection("ImageWallpaper.CanvasEngine#drawFrame");
+            Surface surface = mSurfaceHolder.getSurface();
+            Canvas canvas = mWideColorGamut
+                    ? surface.lockHardwareWideColorGamutCanvas()
+                    : surface.lockHardwareCanvas();
+            if (canvas != null) {
+                Rect dest = mSurfaceHolder.getSurfaceFrame();
+                try {
+                    canvas.drawBitmap(bitmap, null, dest, null);
+                } finally {
+                    surface.unlockCanvasAndPost(canvas);
+                }
+            }
+            Trace.endSection();
+        }
+
+        @VisibleForTesting
+        boolean isBitmapLoaded() {
             return mBitmap != null && !mBitmap.isRecycled();
         }
 
-        /**
-         * Loads the wallpaper on background thread and schedules updating the surface frame,
-         * and if {@code needsDraw} is set also draws a frame.
-         *
-         * If loading is already in-flight, subsequent loads are ignored (but needDraw is or-ed to
-         * the active request).
-         *
-         */
-        private void loadWallpaper(boolean needsDraw) {
-            mNeedsDrawAfterLoadingWallpaper |= needsDraw;
-            if (mLoader != null) {
-                if (DEBUG) {
-                    Log.d(TAG, "Skipping loadWallpaper, already in flight ");
-                }
-                return;
-            }
-            mLoader = new AsyncTask<Void, Void, Bitmap>() {
-                @Override
-                protected Bitmap doInBackground(Void... params) {
-                    Throwable exception;
-                    try {
-                        Bitmap wallpaper = mWallpaperManager.getBitmap(true /* hardware */);
-                        if (wallpaper != null
-                                && wallpaper.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
-                            throw new RuntimeException("Wallpaper is too large to draw!");
-                        }
-                        return wallpaper;
-                    } catch (RuntimeException | OutOfMemoryError e) {
-                        exception = e;
-                    }
-
-                    if (isCancelled()) {
-                        return null;
-                    }
-
-                    // Note that if we do fail at this, and the default wallpaper can't
-                    // be loaded, we will go into a cycle.  Don't do a build where the
-                    // default wallpaper can't be loaded.
-                    Log.w(TAG, "Unable to load wallpaper!", exception);
-                    try {
-                        mWallpaperManager.clear();
-                    } catch (IOException ex) {
-                        // now we're really screwed.
-                        Log.w(TAG, "Unable reset to default wallpaper!", ex);
-                    }
-
-                    if (isCancelled()) {
-                        return null;
-                    }
-
-                    try {
-                        return mWallpaperManager.getBitmap(true /* hardware */);
-                    } catch (RuntimeException | OutOfMemoryError e) {
-                        Log.w(TAG, "Unable to load default wallpaper!", e);
-                    }
-                    return null;
-                }
-
-                @Override
-                protected void onPostExecute(Bitmap bitmap) {
-                    setBitmap(bitmap);
-
-                    if (mNeedsDrawAfterLoadingWallpaper) {
-                        drawFrame(true);
-                    }
-
-                    mLoader = null;
-                    mNeedsDrawAfterLoadingWallpaper = false;
-                    scheduleUnloadWallpaper();
-                }
-            }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        private void unloadBitmapIfNotUsed() {
+            mBackgroundExecutor.execute(this::unloadBitmapIfNotUsedSynchronized);
         }
 
-        private void unloadWallpaper() {
-            if (mLoader != null) {
-                mLoader.cancel(false);
-                mLoader = null;
+        private void unloadBitmapIfNotUsedSynchronized() {
+            synchronized (mLock) {
+                mBitmapUsages -= 1;
+                if (mBitmapUsages <= 0) {
+                    mBitmapUsages = 0;
+                    unloadBitmapInternal();
+                }
             }
+        }
 
+        private void unloadBitmap() {
+            mBackgroundExecutor.execute(this::unloadBitmapSynchronized);
+        }
+
+        private void unloadBitmapSynchronized() {
+            synchronized (mLock) {
+                mBitmapUsages = 0;
+                unloadBitmapInternal();
+            }
+        }
+
+        private void unloadBitmapInternal() {
+            Trace.beginSection("ImageWallpaper.CanvasEngine#unloadBitmap");
             if (mBitmap != null) {
                 mBitmap.recycle();
             }
@@ -750,12 +730,131 @@
             final Surface surface = getSurfaceHolder().getSurface();
             surface.hwuiDestroy();
             mWallpaperManager.forgetLoadedWallpaper();
+            Trace.endSection();
         }
 
-        private void scheduleUnloadWallpaper() {
-            Handler handler = getMainThreadHandler();
-            handler.removeCallbacks(mUnloadWallpaperCallback);
-            handler.postDelayed(mUnloadWallpaperCallback, DELAY_FORGET_WALLPAPER);
+        private void loadWallpaperAndDrawFrameInternal() {
+            Trace.beginSection("ImageWallpaper.CanvasEngine#loadWallpaper");
+            boolean loadSuccess = false;
+            Bitmap bitmap;
+            try {
+                bitmap = mWallpaperManager.getBitmap(false);
+                if (bitmap != null
+                        && bitmap.getByteCount() > RecordingCanvas.MAX_BITMAP_SIZE) {
+                    throw new RuntimeException("Wallpaper is too large to draw!");
+                }
+            } catch (RuntimeException | OutOfMemoryError exception) {
+
+                // Note that if we do fail at this, and the default wallpaper can't
+                // be loaded, we will go into a cycle. Don't do a build where the
+                // default wallpaper can't be loaded.
+                Log.w(TAG, "Unable to load wallpaper!", exception);
+                try {
+                    mWallpaperManager.clear(WallpaperManager.FLAG_SYSTEM);
+                } catch (IOException ex) {
+                    // now we're really screwed.
+                    Log.w(TAG, "Unable reset to default wallpaper!", ex);
+                }
+
+                try {
+                    bitmap = mWallpaperManager.getBitmap(false);
+                } catch (RuntimeException | OutOfMemoryError e) {
+                    Log.w(TAG, "Unable to load default wallpaper!", e);
+                    bitmap = null;
+                }
+            }
+
+            if (bitmap == null) {
+                Log.w(TAG, "Could not load bitmap");
+            } else if (bitmap.isRecycled()) {
+                Log.e(TAG, "Attempt to load a recycled bitmap");
+            } else if (mBitmap == bitmap) {
+                Log.e(TAG, "Loaded a bitmap that was already loaded");
+            } else if (bitmap.getWidth() < 1 || bitmap.getHeight() < 1) {
+                Log.e(TAG, "Attempt to load an invalid wallpaper of length "
+                        + bitmap.getWidth() + "x" + bitmap.getHeight());
+            } else {
+                // at this point, loading is done correctly.
+                loadSuccess = true;
+                // recycle the previously loaded bitmap
+                if (mBitmap != null) {
+                    mBitmap.recycle();
+                }
+                mBitmap = bitmap;
+                mWideColorGamut = mWallpaperManager.wallpaperSupportsWcg(
+                        WallpaperManager.FLAG_SYSTEM);
+
+                // +2 usages for the color extraction and the delayed unload.
+                mBitmapUsages += 2;
+                recomputeColorExtractorMiniBitmap();
+                drawFrameInternal();
+
+                /*
+                 * after loading, the bitmap will be unloaded after all these conditions:
+                 *   - the frame is redrawn
+                 *   - the mini bitmap from color extractor is recomputed
+                 *   - the DELAY_UNLOAD_BITMAP has passed
+                 */
+                mBackgroundExecutor.executeDelayed(
+                        this::unloadBitmapIfNotUsedSynchronized, DELAY_UNLOAD_BITMAP);
+            }
+            // even if the bitmap cannot be loaded, call reportEngineShown
+            if (!loadSuccess) reportEngineShown(false);
+            Trace.endSection();
+        }
+
+        private void onColorsProcessed(List<RectF> regions, List<WallpaperColors> colors) {
+            try {
+                notifyLocalColorsChanged(regions, colors);
+            } catch (RuntimeException e) {
+                Log.e(TAG, e.getMessage(), e);
+            }
+        }
+
+        @VisibleForTesting
+        void recomputeColorExtractorMiniBitmap() {
+            mWallpaperColorExtractor.onBitmapChanged(mBitmap);
+        }
+
+        @VisibleForTesting
+        void onMiniBitmapUpdated() {
+            unloadBitmapIfNotUsed();
+        }
+
+        @Override
+        public boolean supportsLocalColorExtraction() {
+            return true;
+        }
+
+        @Override
+        public void addLocalColorsAreas(@NonNull List<RectF> regions) {
+            // this call will activate the offset notifications
+            // if no colors were being processed before
+            mWallpaperColorExtractor.addLocalColorsAreas(regions);
+        }
+
+        @Override
+        public void removeLocalColorsAreas(@NonNull List<RectF> regions) {
+            // this call will deactivate the offset notifications
+            // if we are no longer processing colors
+            mWallpaperColorExtractor.removeLocalColorAreas(regions);
+        }
+
+        @Override
+        public void onOffsetsChanged(float xOffset, float yOffset,
+                float xOffsetStep, float yOffsetStep,
+                int xPixelOffset, int yPixelOffset) {
+            final int pages;
+            if (xOffsetStep > 0 && xOffsetStep <= 1) {
+                pages = Math.round(1 / xOffsetStep) + 1;
+            } else {
+                pages = 1;
+            }
+            if (pages != mPages || !mPagesComputed) {
+                mPages = pages;
+                mPagesComputed = true;
+                mWallpaperColorExtractor.onPageChanged(mPages);
+            }
         }
 
         @Override
@@ -764,13 +863,46 @@
         }
 
         @Override
-        public void onDisplayChanged(int displayId) {
+        public void onDisplayRemoved(int displayId) {
 
         }
 
         @Override
-        public void onDisplayRemoved(int displayId) {
+        public void onDisplayChanged(int displayId) {
+            // changes the display in the color extractor
+            // the new display dimensions will be used in the next color computation
+            if (displayId == getDisplayContext().getDisplayId()) {
+                getDisplaySizeAndUpdateColorExtractor();
+            }
+        }
 
+        private void getDisplaySizeAndUpdateColorExtractor() {
+            Rect window = getDisplayContext()
+                    .getSystemService(WindowManager.class)
+                    .getCurrentWindowMetrics()
+                    .getBounds();
+            mWallpaperColorExtractor.setDisplayDimensions(window.width(), window.height());
+        }
+
+
+        @Override
+        protected void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
+            super.dump(prefix, fd, out, args);
+            out.print(prefix); out.print("Engine="); out.println(this);
+            out.print(prefix); out.print("valid surface=");
+            out.println(getSurfaceHolder() != null && getSurfaceHolder().getSurface() != null
+                    ? getSurfaceHolder().getSurface().isValid()
+                    : "null");
+
+            out.print(prefix); out.print("surface frame=");
+            out.println(getSurfaceHolder() != null ? getSurfaceHolder().getSurfaceFrame() : "null");
+
+            out.print(prefix); out.print("bitmap=");
+            out.println(mBitmap == null ? "null"
+                    : mBitmap.isRecycled() ? "recycled"
+                    : mBitmap.getWidth() + "x" + mBitmap.getHeight());
+
+            mWallpaperColorExtractor.dump(prefix, fd, out, args);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/ImageCanvasWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/ImageCanvasWallpaperRenderer.java
deleted file mode 100644
index fdba16e..0000000
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/ImageCanvasWallpaperRenderer.java
+++ /dev/null
@@ -1,145 +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.wallpapers.canvas;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.util.Log;
-import android.view.SurfaceHolder;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Helper to draw a wallpaper on a surface.
- * It handles the geometry regarding the dimensions of the display and the wallpaper,
- * and rescales the surface and the wallpaper accordingly.
- */
-public class ImageCanvasWallpaperRenderer {
-
-    private static final String TAG = ImageCanvasWallpaperRenderer.class.getSimpleName();
-    private static final boolean DEBUG = false;
-
-    private SurfaceHolder mSurfaceHolder;
-    //private Bitmap mBitmap = null;
-
-    @VisibleForTesting
-    static final int MIN_SURFACE_WIDTH = 128;
-    @VisibleForTesting
-    static final int MIN_SURFACE_HEIGHT = 128;
-
-    private boolean mSurfaceRedrawNeeded;
-
-    private int mLastSurfaceWidth = -1;
-    private int mLastSurfaceHeight = -1;
-
-    public ImageCanvasWallpaperRenderer(SurfaceHolder surfaceHolder) {
-        mSurfaceHolder = surfaceHolder;
-    }
-
-    /**
-     * Set the surface holder on which to draw.
-     * Should be called when the surface holder is created or changed
-     * @param surfaceHolder the surface on which to draw the wallpaper
-     */
-    public void setSurfaceHolder(SurfaceHolder surfaceHolder) {
-        mSurfaceHolder = surfaceHolder;
-    }
-
-    /**
-     * Check if a surface holder is loaded
-     * @return true if a valid surfaceHolder has been set.
-     */
-    public boolean isSurfaceHolderLoaded() {
-        return mSurfaceHolder != null;
-    }
-
-    /**
-     * Computes and set the surface dimensions, by using the play and the bitmap dimensions.
-     * The Bitmap must be loaded before any call to this function
-     */
-    private boolean updateSurfaceSize(Bitmap bitmap) {
-        int surfaceWidth = Math.max(MIN_SURFACE_WIDTH, bitmap.getWidth());
-        int surfaceHeight = Math.max(MIN_SURFACE_HEIGHT, bitmap.getHeight());
-        boolean surfaceChanged =
-                surfaceWidth != mLastSurfaceWidth || surfaceHeight != mLastSurfaceHeight;
-        if (surfaceChanged) {
-            /*
-             Used a fixed size surface, because we are special.  We can do
-             this because we know the current design of window animations doesn't
-             cause this to break.
-            */
-            mSurfaceHolder.setFixedSize(surfaceWidth, surfaceHeight);
-            mLastSurfaceWidth = surfaceWidth;
-            mLastSurfaceHeight = surfaceHeight;
-        }
-        return surfaceChanged;
-    }
-
-    /**
-     * Draw a the wallpaper on the surface.
-     * The bitmap and the surface must be loaded before calling
-     * this function.
-     * @param forceRedraw redraw the wallpaper even if no changes are detected
-     */
-    public void drawFrame(Bitmap bitmap, boolean forceRedraw) {
-
-        if (bitmap == null || bitmap.isRecycled()) {
-            Log.e(TAG, "Attempt to draw frame before background is loaded:");
-            return;
-        }
-
-        if (bitmap.getWidth() < 1 || bitmap.getHeight() < 1) {
-            Log.e(TAG, "Attempt to set an invalid wallpaper of length "
-                    + bitmap.getWidth() + "x" + bitmap.getHeight());
-            return;
-        }
-
-        mSurfaceRedrawNeeded |= forceRedraw;
-        boolean surfaceChanged = updateSurfaceSize(bitmap);
-
-        boolean redrawNeeded = surfaceChanged || mSurfaceRedrawNeeded;
-        mSurfaceRedrawNeeded = false;
-
-        if (!redrawNeeded) {
-            if (DEBUG) {
-                Log.d(TAG, "Suppressed drawFrame since redraw is not needed ");
-            }
-            return;
-        }
-
-        if (DEBUG) {
-            Log.d(TAG, "Redrawing wallpaper");
-        }
-        drawWallpaperWithCanvas(bitmap);
-    }
-
-    @VisibleForTesting
-    void drawWallpaperWithCanvas(Bitmap bitmap) {
-        Canvas c = mSurfaceHolder.lockHardwareCanvas();
-        if (c != null) {
-            Rect dest = mSurfaceHolder.getSurfaceFrame();
-            Log.i(TAG, "Redrawing in rect: " + dest + " with surface size: "
-                    + mLastSurfaceWidth + "x" + mLastSurfaceHeight);
-            try {
-                c.drawBitmap(bitmap, null, dest, null);
-            } finally {
-                mSurfaceHolder.unlockCanvasAndPost(c);
-            }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/WallpaperColorExtractor.java b/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/WallpaperColorExtractor.java
new file mode 100644
index 0000000..e2e4555
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/canvas/WallpaperColorExtractor.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.systemui.wallpapers.canvas;
+
+import android.app.WallpaperColors;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Trace;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.MathUtils;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.util.Assert;
+import com.android.systemui.wallpapers.ImageWallpaper;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * This class is used by the {@link ImageWallpaper} to extract colors from areas of a wallpaper.
+ * It uses a background executor, and uses callbacks to inform that the work is done.
+ * It uses  a downscaled version of the wallpaper to extract the colors.
+ */
+public class WallpaperColorExtractor {
+
+    private Bitmap mMiniBitmap;
+
+    @VisibleForTesting
+    static final int SMALL_SIDE = 128;
+
+    private static final String TAG = WallpaperColorExtractor.class.getSimpleName();
+    private static final @NonNull RectF LOCAL_COLOR_BOUNDS =
+            new RectF(0, 0, 1, 1);
+
+    private int mDisplayWidth = -1;
+    private int mDisplayHeight = -1;
+    private int mPages = -1;
+    private int mBitmapWidth = -1;
+    private int mBitmapHeight = -1;
+
+    private final Object mLock = new Object();
+
+    private final List<RectF> mPendingRegions = new ArrayList<>();
+    private final Set<RectF> mProcessedRegions = new ArraySet<>();
+
+    @Background
+    private final Executor mBackgroundExecutor;
+
+    private final WallpaperColorExtractorCallback mWallpaperColorExtractorCallback;
+
+    /**
+     * Interface to handle the callbacks after the different steps of the color extraction
+     */
+    public interface WallpaperColorExtractorCallback {
+        /**
+         * Callback after the colors of new regions have been extracted
+         * @param regions the list of new regions that have been processed
+         * @param colors the resulting colors for these regions, in the same order as the regions
+         */
+        void onColorsProcessed(List<RectF> regions, List<WallpaperColors> colors);
+
+        /**
+         * Callback after the mini bitmap is computed, to indicate that the wallpaper bitmap is
+         * no longer used by the color extractor and can be safely recycled
+         */
+        void onMiniBitmapUpdated();
+
+        /**
+         * Callback to inform that the extractor has started processing colors
+         */
+        void onActivated();
+
+        /**
+         * Callback to inform that no more colors are being processed
+         */
+        void onDeactivated();
+    }
+
+    /**
+     * Creates a new color extractor.
+     * @param backgroundExecutor the executor on which the color extraction will be performed
+     * @param wallpaperColorExtractorCallback an interface to handle the callbacks from
+     *                                        the color extractor.
+     */
+    public WallpaperColorExtractor(@Background Executor backgroundExecutor,
+            WallpaperColorExtractorCallback wallpaperColorExtractorCallback) {
+        mBackgroundExecutor = backgroundExecutor;
+        mWallpaperColorExtractorCallback = wallpaperColorExtractorCallback;
+    }
+
+    /**
+     * Used by the outside to inform that the display size has changed.
+     * The new display size will be used in the next computations, but the current colors are
+     * not recomputed.
+     */
+    public void setDisplayDimensions(int displayWidth, int displayHeight) {
+        mBackgroundExecutor.execute(() ->
+                setDisplayDimensionsSynchronized(displayWidth, displayHeight));
+    }
+
+    private void setDisplayDimensionsSynchronized(int displayWidth, int displayHeight) {
+        synchronized (mLock) {
+            if (displayWidth == mDisplayWidth && displayHeight == mDisplayHeight) return;
+            mDisplayWidth = displayWidth;
+            mDisplayHeight = displayHeight;
+            processColorsInternal();
+        }
+    }
+
+    /**
+     * @return whether color extraction is currently in use
+     */
+    private boolean isActive() {
+        return mPendingRegions.size() + mProcessedRegions.size() > 0;
+    }
+
+    /**
+     * Should be called when the wallpaper is changed.
+     * This will recompute the mini bitmap
+     * and restart the extraction of all areas
+     * @param bitmap the new wallpaper
+     */
+    public void onBitmapChanged(@NonNull Bitmap bitmap) {
+        mBackgroundExecutor.execute(() -> onBitmapChangedSynchronized(bitmap));
+    }
+
+    private void onBitmapChangedSynchronized(@NonNull Bitmap bitmap) {
+        synchronized (mLock) {
+            if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
+                Log.e(TAG, "Attempt to extract colors from an invalid bitmap");
+                return;
+            }
+            mBitmapWidth = bitmap.getWidth();
+            mBitmapHeight = bitmap.getHeight();
+            mMiniBitmap = createMiniBitmap(bitmap);
+            mWallpaperColorExtractorCallback.onMiniBitmapUpdated();
+            recomputeColors();
+        }
+    }
+
+    /**
+     * Should be called when the number of pages is changed
+     * This will restart the extraction of all areas
+     * @param pages the total number of pages of the launcher
+     */
+    public void onPageChanged(int pages) {
+        mBackgroundExecutor.execute(() -> onPageChangedSynchronized(pages));
+    }
+
+    private void onPageChangedSynchronized(int pages) {
+        synchronized (mLock) {
+            if (mPages == pages) return;
+            mPages = pages;
+            if (mMiniBitmap != null && !mMiniBitmap.isRecycled()) {
+                recomputeColors();
+            }
+        }
+    }
+
+    // helper to recompute colors, to be called in synchronized methods
+    private void recomputeColors() {
+        mPendingRegions.addAll(mProcessedRegions);
+        mProcessedRegions.clear();
+        processColorsInternal();
+    }
+
+    /**
+     * Add new regions to extract
+     * This will trigger the color extraction and call the callback only for these new regions
+     * @param regions The areas of interest in our wallpaper (in screen pixel coordinates)
+     */
+    public void addLocalColorsAreas(@NonNull List<RectF> regions) {
+        if (regions.size() > 0) {
+            mBackgroundExecutor.execute(() -> addLocalColorsAreasSynchronized(regions));
+        } else {
+            Log.w(TAG, "Attempt to add colors with an empty list");
+        }
+    }
+
+    private void addLocalColorsAreasSynchronized(@NonNull List<RectF> regions) {
+        synchronized (mLock) {
+            boolean wasActive = isActive();
+            mPendingRegions.addAll(regions);
+            if (!wasActive && isActive()) {
+                mWallpaperColorExtractorCallback.onActivated();
+            }
+            processColorsInternal();
+        }
+    }
+
+    /**
+     * Remove regions to extract. If a color extraction is ongoing does not stop it.
+     * But if there are subsequent changes that restart the extraction, the removed regions
+     * will not be recomputed.
+     * @param regions The areas of interest in our wallpaper (in screen pixel coordinates)
+     */
+    public void removeLocalColorAreas(@NonNull List<RectF> regions) {
+        mBackgroundExecutor.execute(() -> removeLocalColorAreasSynchronized(regions));
+    }
+
+    private void removeLocalColorAreasSynchronized(@NonNull List<RectF> regions) {
+        synchronized (mLock) {
+            boolean wasActive = isActive();
+            mPendingRegions.removeAll(regions);
+            regions.forEach(mProcessedRegions::remove);
+            if (wasActive && !isActive()) {
+                mWallpaperColorExtractorCallback.onDeactivated();
+            }
+        }
+    }
+
+    /**
+     * Clean up the memory (in particular, the mini bitmap) used by this class.
+     */
+    public void cleanUp() {
+        mBackgroundExecutor.execute(this::cleanUpSynchronized);
+    }
+
+    private void cleanUpSynchronized() {
+        synchronized (mLock) {
+            if (mMiniBitmap != null) {
+                mMiniBitmap.recycle();
+                mMiniBitmap = null;
+            }
+            mProcessedRegions.clear();
+            mPendingRegions.clear();
+        }
+    }
+
+    private Bitmap createMiniBitmap(@NonNull Bitmap bitmap) {
+        Trace.beginSection("WallpaperColorExtractor#createMiniBitmap");
+        // if both sides of the image are larger than SMALL_SIDE, downscale the bitmap.
+        int smallestSide = Math.min(bitmap.getWidth(), bitmap.getHeight());
+        float scale = Math.min(1.0f, (float) SMALL_SIDE / smallestSide);
+        Bitmap result = createMiniBitmap(bitmap,
+                (int) (scale * bitmap.getWidth()),
+                (int) (scale * bitmap.getHeight()));
+        Trace.endSection();
+        return result;
+    }
+
+    @VisibleForTesting
+    Bitmap createMiniBitmap(@NonNull Bitmap bitmap, int width, int height) {
+        return Bitmap.createScaledBitmap(bitmap, width, height, false);
+    }
+
+    private WallpaperColors getLocalWallpaperColors(@NonNull RectF area) {
+        RectF imageArea = pageToImgRect(area);
+        if (imageArea == null || !LOCAL_COLOR_BOUNDS.contains(imageArea)) {
+            return null;
+        }
+        Rect subImage = new Rect(
+                (int) Math.floor(imageArea.left * mMiniBitmap.getWidth()),
+                (int) Math.floor(imageArea.top * mMiniBitmap.getHeight()),
+                (int) Math.ceil(imageArea.right * mMiniBitmap.getWidth()),
+                (int) Math.ceil(imageArea.bottom * mMiniBitmap.getHeight()));
+        if (subImage.isEmpty()) {
+            // Do not notify client. treat it as too small to sample
+            return null;
+        }
+        return getLocalWallpaperColors(subImage);
+    }
+
+    @VisibleForTesting
+    WallpaperColors getLocalWallpaperColors(@NonNull Rect subImage) {
+        Assert.isNotMainThread();
+        Bitmap colorImg = Bitmap.createBitmap(mMiniBitmap,
+                subImage.left, subImage.top, subImage.width(), subImage.height());
+        return WallpaperColors.fromBitmap(colorImg);
+    }
+
+    /**
+     * Transform the logical coordinates into wallpaper coordinates.
+     *
+     * Logical coordinates are organised such that the various pages are non-overlapping. So,
+     * if there are n pages, the first page will have its X coordinate on the range [0-1/n].
+     *
+     * The real pages are overlapping. If the Wallpaper are a width Ww and the screen a width
+     * Ws, the relative width of a page Wr is Ws/Ww. This does not change if the number of
+     * pages increase.
+     * If there are n pages, the page k starts at the offset k * (1 - Wr) / (n - 1), as the
+     * last page is at position (1-Wr) and the others are regularly spread on the range [0-
+     * (1-Wr)].
+     */
+    private RectF pageToImgRect(RectF area) {
+        // Width of a page for the caller of this API.
+        float virtualPageWidth = 1f / (float) mPages;
+        float leftPosOnPage = (area.left % virtualPageWidth) / virtualPageWidth;
+        float rightPosOnPage = (area.right % virtualPageWidth) / virtualPageWidth;
+        int currentPage = (int) Math.floor(area.centerX() / virtualPageWidth);
+
+        if (mDisplayWidth <= 0 || mDisplayHeight <= 0) {
+            Log.e(TAG, "Trying to extract colors with invalid display dimensions");
+            return null;
+        }
+
+        RectF imgArea = new RectF();
+        imgArea.bottom = area.bottom;
+        imgArea.top = area.top;
+
+        float imageScale = Math.min(((float) mBitmapHeight) / mDisplayHeight, 1);
+        float mappedScreenWidth = mDisplayWidth * imageScale;
+        float pageWidth = Math.min(1.0f,
+                mBitmapWidth > 0 ? mappedScreenWidth / (float) mBitmapWidth : 1.f);
+        float pageOffset = (1 - pageWidth) / (float) (mPages - 1);
+
+        imgArea.left = MathUtils.constrain(
+                leftPosOnPage * pageWidth + currentPage * pageOffset, 0, 1);
+        imgArea.right = MathUtils.constrain(
+                rightPosOnPage * pageWidth + currentPage * pageOffset, 0, 1);
+        if (imgArea.left > imgArea.right) {
+            // take full page
+            imgArea.left = 0;
+            imgArea.right = 1;
+        }
+        return imgArea;
+    }
+
+    /**
+     * Extract the colors from the pending regions,
+     * then notify the callback with the resulting colors for these regions
+     * This method should only be called synchronously
+     */
+    private void processColorsInternal() {
+        /*
+         * if the miniBitmap is not yet loaded, that means the onBitmapChanged has not yet been
+         * called, and thus the wallpaper is not yet loaded. In that case, exit, the function
+         * will be called again when the bitmap is loaded and the miniBitmap is computed.
+         */
+        if (mMiniBitmap == null || mMiniBitmap.isRecycled())  return;
+
+        /*
+         * if the screen size or number of pages is not yet known, exit
+         * the function will be called again once the screen size and page are known
+         */
+        if (mDisplayWidth < 0 || mDisplayHeight < 0 || mPages < 0) return;
+
+        Trace.beginSection("WallpaperColorExtractor#processColorsInternal");
+        List<WallpaperColors> processedColors = new ArrayList<>();
+        for (int i = 0; i < mPendingRegions.size(); i++) {
+            RectF nextArea = mPendingRegions.get(i);
+            WallpaperColors colors = getLocalWallpaperColors(nextArea);
+
+            mProcessedRegions.add(nextArea);
+            processedColors.add(colors);
+        }
+        List<RectF> processedRegions = new ArrayList<>(mPendingRegions);
+        mPendingRegions.clear();
+        Trace.endSection();
+
+        mWallpaperColorExtractorCallback.onColorsProcessed(processedRegions, processedColors);
+    }
+
+    /**
+     * Called to dump current state.
+     * @param prefix prefix.
+     * @param fd fd.
+     * @param out out.
+     * @param args args.
+     */
+    public void dump(String prefix, FileDescriptor fd, PrintWriter out, String[] args) {
+        out.print(prefix); out.print("display="); out.println(mDisplayWidth + "x" + mDisplayHeight);
+        out.print(prefix); out.print("mPages="); out.println(mPages);
+
+        out.print(prefix); out.print("bitmap dimensions=");
+        out.println(mBitmapWidth + "x" + mBitmapHeight);
+
+        out.print(prefix); out.print("bitmap=");
+        out.println(mMiniBitmap == null ? "null"
+                : mMiniBitmap.isRecycled() ? "recycled"
+                : mMiniBitmap.getWidth() + "x" + mMiniBitmap.getHeight());
+
+        out.print(prefix); out.print("PendingRegions size="); out.print(mPendingRegions.size());
+        out.print(prefix); out.print("ProcessedRegions size="); out.print(mProcessedRegions.size());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
index c2c7dde..ecf7e0d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextManagerTest.java
@@ -29,7 +29,6 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -171,7 +170,7 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
         when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -191,7 +190,7 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
         when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
                 TelephonyManager.SIM_STATE_CARD_IO_ERROR);
@@ -224,7 +223,7 @@
     @Test
     public void testWrongSlots() {
         reset(mCarrierTextCallback);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
                 new ArrayList<>());
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_CARD_IO_ERROR);
@@ -238,7 +237,7 @@
     @Test
     public void testMoreSlotsThanSubs() {
         reset(mCarrierTextCallback);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
                 new ArrayList<>());
 
         // STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
@@ -289,7 +288,7 @@
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -314,7 +313,7 @@
         list.add(TEST_SUBSCRIPTION_ROAMING);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -339,7 +338,7 @@
         list.add(TEST_SUBSCRIPTION_NULL);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -364,7 +363,7 @@
         list.add(TEST_SUBSCRIPTION_NULL);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
         mockWifi();
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -396,7 +395,7 @@
     @Test
     public void testCreateInfo_noSubscriptions() {
         reset(mCarrierTextCallback);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(
                 new ArrayList<>());
 
         ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
@@ -421,7 +420,7 @@
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
                 TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -446,7 +445,7 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
                 .thenReturn(TelephonyManager.SIM_STATE_READY)
                 .thenReturn(TelephonyManager.SIM_STATE_NOT_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -471,7 +470,7 @@
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
                 .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
                 .thenReturn(TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
@@ -498,7 +497,7 @@
                 .thenReturn(TelephonyManager.SIM_STATE_READY)
                 .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
                 .thenReturn(TelephonyManager.SIM_STATE_READY);
-        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo()).thenReturn(list);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextManager.CarrierTextCallbackInfo> captor =
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
index 25e7dbb..8a2c354 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt
@@ -22,9 +22,11 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.plugins.Clock
 import com.android.systemui.plugins.ClockAnimations
+import com.android.systemui.plugins.ClockController
 import com.android.systemui.plugins.ClockEvents
+import com.android.systemui.plugins.ClockFaceController
+import com.android.systemui.plugins.ClockFaceEvents
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.BatteryController
 import com.android.systemui.statusbar.policy.ConfigurationController
@@ -40,6 +42,7 @@
 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.Mock
@@ -61,17 +64,25 @@
     @Mock private lateinit var configurationController: ConfigurationController
     @Mock private lateinit var animations: ClockAnimations
     @Mock private lateinit var events: ClockEvents
-    @Mock private lateinit var clock: Clock
+    @Mock private lateinit var clock: ClockController
     @Mock private lateinit var mainExecutor: Executor
     @Mock private lateinit var bgExecutor: Executor
     @Mock private lateinit var featureFlags: FeatureFlags
+    @Mock private lateinit var smallClockController: ClockFaceController
+    @Mock private lateinit var largeClockController: ClockFaceController
+    @Mock private lateinit var smallClockEvents: ClockFaceEvents
+    @Mock private lateinit var largeClockEvents: ClockFaceEvents
 
     private lateinit var clockEventController: ClockEventController
 
     @Before
     fun setUp() {
-        whenever(clock.smallClock).thenReturn(TextView(context))
-        whenever(clock.largeClock).thenReturn(TextView(context))
+        whenever(clock.smallClock).thenReturn(smallClockController)
+        whenever(clock.largeClock).thenReturn(largeClockController)
+        whenever(smallClockController.view).thenReturn(TextView(context))
+        whenever(largeClockController.view).thenReturn(TextView(context))
+        whenever(smallClockController.events).thenReturn(smallClockEvents)
+        whenever(largeClockController.events).thenReturn(largeClockEvents)
         whenever(clock.events).thenReturn(events)
         whenever(clock.animations).thenReturn(animations)
 
@@ -107,7 +118,8 @@
     @Test
     fun themeChanged_verifyClockPaletteUpdated() {
         clockEventController.clock = clock
-        verify(events).onColorPaletteChanged(any(), any(), any())
+        verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
+        verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
 
         clockEventController.registerListeners()
 
@@ -115,13 +127,14 @@
         verify(configurationController).addCallback(capture(captor))
         captor.value.onThemeChanged()
 
-        verify(events, times(2)).onColorPaletteChanged(any(), any(), any())
+        verify(events).onColorPaletteChanged(any())
     }
 
     @Test
     fun fontChanged_verifyFontSizeUpdated() {
         clockEventController.clock = clock
-        verify(events).onColorPaletteChanged(any(), any(), any())
+        verify(smallClockEvents).onRegionDarknessChanged(anyBoolean())
+        verify(largeClockEvents).onRegionDarknessChanged(anyBoolean())
 
         clockEventController.registerListeners()
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index 635ee9e..400caa3 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -45,7 +45,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
-import com.android.systemui.plugins.Clock;
+import com.android.systemui.plugins.ClockController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.clocks.AnimatableClockView;
 import com.android.systemui.shared.clocks.ClockRegistry;
@@ -87,7 +87,7 @@
     @Mock
     KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
     @Mock
-    private Clock mClock;
+    private ClockController mClock;
     @Mock
     DumpManager mDumpManager;
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index a0295d0..254f953 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -41,7 +41,8 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.Clock;
+import com.android.systemui.plugins.ClockController;
+import com.android.systemui.plugins.ClockFaceController;
 import com.android.systemui.statusbar.StatusBarState;
 
 import org.junit.Before;
@@ -61,7 +62,13 @@
     ViewGroup mMockKeyguardSliceView;
 
     @Mock
-    Clock mClock;
+    ClockController mClock;
+
+    @Mock
+    ClockFaceController mSmallClock;
+
+    @Mock
+    ClockFaceController mLargeClock;
 
     private FrameLayout mSmallClockFrame;
     private FrameLayout mLargeClockFrame;
@@ -75,8 +82,11 @@
         when(mMockKeyguardSliceView.findViewById(R.id.keyguard_status_area))
                 .thenReturn(mMockKeyguardSliceView);
 
-        when(mClock.getSmallClock()).thenReturn(new TextView(getContext()));
-        when(mClock.getLargeClock()).thenReturn(new TextView(getContext()));
+        when(mClock.getSmallClock()).thenReturn(mSmallClock);
+        when(mClock.getLargeClock()).thenReturn(mLargeClock);
+
+        when(mSmallClock.getView()).thenReturn(new TextView(getContext()));
+        when(mLargeClock.getView()).thenReturn(new TextView(getContext()));
 
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
         layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@@ -124,41 +134,49 @@
     public void onPluginConnected_showClock() {
         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
 
-        assertEquals(mClock.getSmallClock().getParent(), mSmallClockFrame);
-        assertEquals(mClock.getLargeClock().getParent(), mLargeClockFrame);
+        assertEquals(mClock.getSmallClock().getView().getParent(), mSmallClockFrame);
+        assertEquals(mClock.getLargeClock().getView().getParent(), mLargeClockFrame);
     }
 
     @Test
     public void onPluginConnected_showSecondPluginClock() {
         // GIVEN a plugin has already connected
-        Clock otherClock = mock(Clock.class);
-        when(otherClock.getSmallClock()).thenReturn(new TextView(getContext()));
-        when(otherClock.getLargeClock()).thenReturn(new TextView(getContext()));
+        ClockController otherClock = mock(ClockController.class);
+        ClockFaceController smallClock = mock(ClockFaceController.class);
+        ClockFaceController largeClock = mock(ClockFaceController.class);
+        when(otherClock.getSmallClock()).thenReturn(smallClock);
+        when(otherClock.getLargeClock()).thenReturn(largeClock);
+        when(smallClock.getView()).thenReturn(new TextView(getContext()));
+        when(largeClock.getView()).thenReturn(new TextView(getContext()));
         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
         mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
 
         // THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
-        assertThat(otherClock.getSmallClock().getParent()).isEqualTo(mSmallClockFrame);
-        assertThat(otherClock.getLargeClock().getParent()).isEqualTo(mLargeClockFrame);
-        assertThat(mClock.getSmallClock().getParent()).isNull();
-        assertThat(mClock.getLargeClock().getParent()).isNull();
+        assertThat(otherClock.getSmallClock().getView().getParent()).isEqualTo(mSmallClockFrame);
+        assertThat(otherClock.getLargeClock().getView().getParent()).isEqualTo(mLargeClockFrame);
+        assertThat(mClock.getSmallClock().getView().getParent()).isNull();
+        assertThat(mClock.getLargeClock().getView().getParent()).isNull();
     }
 
     @Test
     public void onPluginDisconnected_secondOfTwoDisconnected() {
         // GIVEN two plugins are connected
-        Clock otherClock = mock(Clock.class);
-        when(otherClock.getSmallClock()).thenReturn(new TextView(getContext()));
-        when(otherClock.getLargeClock()).thenReturn(new TextView(getContext()));
+        ClockController otherClock = mock(ClockController.class);
+        ClockFaceController smallClock = mock(ClockFaceController.class);
+        ClockFaceController largeClock = mock(ClockFaceController.class);
+        when(otherClock.getSmallClock()).thenReturn(smallClock);
+        when(otherClock.getLargeClock()).thenReturn(largeClock);
+        when(smallClock.getView()).thenReturn(new TextView(getContext()));
+        when(largeClock.getView()).thenReturn(new TextView(getContext()));
         mKeyguardClockSwitch.setClock(otherClock, StatusBarState.KEYGUARD);
         mKeyguardClockSwitch.setClock(mClock, StatusBarState.KEYGUARD);
         // WHEN the second plugin is disconnected
         mKeyguardClockSwitch.setClock(null, StatusBarState.KEYGUARD);
         // THEN nothing should be shown
-        assertThat(otherClock.getSmallClock().getParent()).isNull();
-        assertThat(otherClock.getLargeClock().getParent()).isNull();
-        assertThat(mClock.getSmallClock().getParent()).isNull();
-        assertThat(mClock.getLargeClock().getParent()).isNull();
+        assertThat(otherClock.getSmallClock().getView().getParent()).isNull();
+        assertThat(otherClock.getLargeClock().getView().getParent()).isNull();
+        assertThat(mClock.getSmallClock().getView().getParent()).isNull();
+        assertThat(mClock.getLargeClock().getView().getParent()).isNull();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 5213714..52f8825 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -387,7 +387,7 @@
                     0 /* flags */);
             users.add(new UserRecord(info, null, false /* isGuest */, false /* isCurrent */,
                     false /* isAddUser */, false /* isRestricted */, true /* isSwitchToEnabled */,
-                    false /* isAddSupervisedUser */));
+                    false /* isAddSupervisedUser */, null /* enforcedAdmin */));
         }
         return users;
     }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 9c64c1b..784e7dd 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -59,6 +59,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
+import android.hardware.SensorPrivacyManager;
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.BiometricSourceType;
@@ -79,13 +80,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.service.dreams.IDreamManager;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
 import android.testing.TestableLooper;
 
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
@@ -170,6 +171,8 @@
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
     @Mock
+    private IDreamManager mDreamManager;
+    @Mock
     private KeyguardBypassController mKeyguardBypassController;
     @Mock
     private SubscriptionManager mSubscriptionManager;
@@ -178,6 +181,8 @@
     @Mock
     private TelephonyManager mTelephonyManager;
     @Mock
+    private SensorPrivacyManager mSensorPrivacyManager;
+    @Mock
     private StatusBarStateController mStatusBarStateController;
     @Mock
     private AuthController mAuthController;
@@ -219,7 +224,6 @@
     private TestableLooper mTestableLooper;
     private Handler mHandler;
     private TestableKeyguardUpdateMonitor mKeyguardUpdateMonitor;
-    private TestableContext mSpiedContext;
     private MockitoSession mMockitoSession;
     private StatusBarStateController.StateListener mStatusBarStateListener;
     private IBiometricEnabledOnKeyguardCallback mBiometricEnabledOnKeyguardCallback;
@@ -228,9 +232,6 @@
     @Before
     public void setup() throws RemoteException {
         MockitoAnnotations.initMocks(this);
-        mSpiedContext = spy(mContext);
-        when(mPackageManager.hasSystemFeature(anyString())).thenReturn(true);
-        when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager);
         when(mActivityService.getCurrentUser()).thenReturn(mCurrentUserInfo);
         when(mActivityService.getCurrentUserId()).thenReturn(mCurrentUserId);
         when(mFaceManager.isHardwareDetected()).thenReturn(true);
@@ -279,14 +280,6 @@
                 .thenReturn(new ServiceState());
         when(mLockPatternUtils.getLockSettings()).thenReturn(mLockSettings);
         when(mAuthController.isUdfpsEnrolled(anyInt())).thenReturn(false);
-        mSpiedContext.addMockSystemService(TrustManager.class, mTrustManager);
-        mSpiedContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
-        mSpiedContext.addMockSystemService(BiometricManager.class, mBiometricManager);
-        mSpiedContext.addMockSystemService(FaceManager.class, mFaceManager);
-        mSpiedContext.addMockSystemService(UserManager.class, mUserManager);
-        mSpiedContext.addMockSystemService(DevicePolicyManager.class, mDevicePolicyManager);
-        mSpiedContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
-        mSpiedContext.addMockSystemService(TelephonyManager.class, mTelephonyManager);
 
         mMockitoSession = ExtendedMockito.mockitoSession()
                 .spyStatic(SubscriptionManager.class)
@@ -301,7 +294,7 @@
 
         mTestableLooper = TestableLooper.get(this);
         allowTestableLooperAsMainThread();
-        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
 
         verify(mBiometricManager)
                 .registerEnabledOnKeyguardCallback(mBiometricEnabledCallbackArgCaptor.capture());
@@ -356,7 +349,7 @@
         when(mTelephonyManager.getSimState(anyInt())).thenReturn(state);
         when(mSubscriptionManager.getSubscriptionIds(anyInt())).thenReturn(new int[]{subId});
 
-        KeyguardUpdateMonitor testKUM = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        KeyguardUpdateMonitor testKUM = new TestableKeyguardUpdateMonitor(mContext);
 
         mTestableLooper.processAllMessages();
 
@@ -614,7 +607,7 @@
     public void testTriesToAuthenticate_whenKeyguard() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
     }
 
@@ -624,7 +617,7 @@
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
 
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                 anyBoolean());
     }
@@ -637,7 +630,7 @@
 
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                 anyBoolean());
     }
@@ -661,7 +654,7 @@
 
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
 
         // Stop scanning when bouncer becomes visible
@@ -675,7 +668,7 @@
 
     @Test
     public void testTriesToAuthenticate_whenAssistant() {
-        mKeyguardUpdateMonitor.setKeyguardOccluded(true);
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
         mKeyguardUpdateMonitor.setAssistantVisible(true);
 
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
@@ -690,7 +683,7 @@
         mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
                 KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
                 new ArrayList<>());
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
     }
 
@@ -700,7 +693,7 @@
         mTestableLooper.processAllMessages();
         mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
                 KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */, new ArrayList<>());
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                 anyBoolean());
     }
@@ -712,7 +705,7 @@
         when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
                 KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
 
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                 anyBoolean());
     }
@@ -724,7 +717,7 @@
         when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
                 KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
 
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
     }
 
@@ -745,7 +738,7 @@
     public void testFaceAndFingerprintLockout_onlyFace() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
 
         faceAuthLockedOut();
 
@@ -756,7 +749,7 @@
     public void testFaceAndFingerprintLockout_onlyFingerprint() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
 
         mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
                 .onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT_PERMANENT, "");
@@ -768,7 +761,7 @@
     public void testFaceAndFingerprintLockout() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
 
         faceAuthLockedOut();
         mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
@@ -867,7 +860,7 @@
 
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
 
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
         verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
@@ -912,7 +905,7 @@
         mTestableLooper.processAllMessages();
 
         List<SubscriptionInfo> listToVerify = mKeyguardUpdateMonitor
-                .getFilteredSubscriptionInfo(false);
+                .getFilteredSubscriptionInfo();
         assertThat(listToVerify.size()).isEqualTo(1);
         assertThat(listToVerify.get(0)).isEqualTo(TEST_SUBSCRIPTION_2);
     }
@@ -1040,8 +1033,7 @@
     public void testOccludingAppFingerprintListeningState() {
         // GIVEN keyguard isn't visible (app occluding)
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
-        mKeyguardUpdateMonitor.setKeyguardOccluded(true);
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(false);
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
         when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
 
         // THEN we shouldn't listen for fingerprints
@@ -1056,8 +1048,7 @@
     public void testOccludingAppRequestsFingerprint() {
         // GIVEN keyguard isn't visible (app occluding)
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
-        mKeyguardUpdateMonitor.setKeyguardOccluded(true);
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(false);
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
 
         // WHEN an occluding app requests fp
         mKeyguardUpdateMonitor.requestFingerprintAuthOnOccludingApp(true);
@@ -1149,7 +1140,7 @@
         setKeyguardBouncerVisibility(false /* isVisible */);
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         when(mKeyguardBypassController.canBypass()).thenReturn(true);
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
 
         // WHEN status bar state reports a change to the keyguard that would normally indicate to
         // start running face auth
@@ -1160,8 +1151,9 @@
         // listening state to update
         assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isEqualTo(false);
 
-        // WHEN biometric listening state is updated
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        // WHEN biometric listening state is updated when showing state changes from false => true
+        mKeyguardUpdateMonitor.setKeyguardShowing(false, false);
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
 
         // THEN face unlock is running
         assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isEqualTo(true);
@@ -1202,9 +1194,9 @@
     @Test
     public void testShouldListenForFace_whenFaceManagerNotAvailable_returnsFalse() {
         cleanupKeyguardUpdateMonitor();
-        mSpiedContext.addMockSystemService(FaceManager.class, null);
-        when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
-        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        mFaceManager = null;
+
+        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
 
         assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
     }
@@ -1258,7 +1250,7 @@
         // This disables face auth
         when(mUserManager.isPrimaryUser()).thenReturn(false);
         mKeyguardUpdateMonitor =
-                new TestableKeyguardUpdateMonitor(mSpiedContext);
+                new TestableKeyguardUpdateMonitor(mContext);
 
         // Face auth should run when the following is true.
         keyguardNotGoingAway();
@@ -1482,6 +1474,27 @@
     }
 
     @Test
+    public void testShouldListenForFace_udfpsBouncerIsShowingButDeviceGoingToSleep_returnsFalse()
+            throws RemoteException {
+        // Preconditions for face auth to run
+        keyguardNotGoingAway();
+        currentUserIsPrimary();
+        currentUserDoesNotHaveTrust();
+        biometricsNotDisabledThroughDevicePolicyManager();
+        biometricsEnabledForCurrentUser();
+        userNotCurrentlySwitching();
+        deviceNotGoingToSleep();
+        mKeyguardUpdateMonitor.setUdfpsBouncerShowing(true);
+        mTestableLooper.processAllMessages();
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+
+        deviceGoingToSleep();
+        mTestableLooper.processAllMessages();
+
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
+    }
+
+    @Test
     public void testShouldListenForFace_whenFaceIsLockedOut_returnsFalse()
             throws RemoteException {
         // Preconditions for face auth to run
@@ -1506,7 +1519,7 @@
     public void testFingerprintCanAuth_whenCancellationNotReceivedAndAuthFailed() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
         mTestableLooper.processAllMessages();
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        keyguardIsVisible();
 
         verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
         verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
@@ -1515,7 +1528,7 @@
         mKeyguardUpdateMonitor.onFaceAuthenticated(0, false);
         // Make sure keyguard is going away after face auth attempt, and that it calls
         // updateBiometricStateListeningState.
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(false);
+        mKeyguardUpdateMonitor.setKeyguardShowing(false, false);
         mTestableLooper.processAllMessages();
 
         verify(mHandler).postDelayed(mKeyguardUpdateMonitor.mFpCancelNotReceived,
@@ -1527,15 +1540,16 @@
         verify(mHandler, times(1)).removeCallbacks(mKeyguardUpdateMonitor.mFpCancelNotReceived);
         mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
         mTestableLooper.processAllMessages();
-        assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(anyBoolean())).isEqualTo(true);
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(false)).isEqualTo(true);
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(true);
     }
 
     @Test
     public void testFingerAcquired_wakesUpPowerManager() {
         cleanupKeyguardUpdateMonitor();
-        mSpiedContext.getOrCreateTestableResources().addOverride(
+        mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.kg_wake_on_acquire_start, true);
-        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
         fingerprintAcquireStart();
 
         verify(mPowerManager).wakeUp(anyLong(), anyInt(), anyString());
@@ -1544,9 +1558,9 @@
     @Test
     public void testFingerAcquired_doesNotWakeUpPowerManager() {
         cleanupKeyguardUpdateMonitor();
-        mSpiedContext.getOrCreateTestableResources().addOverride(
+        mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.kg_wake_on_acquire_start, false);
-        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mSpiedContext);
+        mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
         fingerprintAcquireStart();
 
         verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString());
@@ -1574,7 +1588,7 @@
     }
 
     private void keyguardIsVisible() {
-        mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+        mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
     }
 
     private void triggerAuthInterrupt() {
@@ -1667,6 +1681,10 @@
         mKeyguardUpdateMonitor.dispatchFinishedGoingToSleep(/* value doesn't matter */1);
     }
 
+    private void deviceGoingToSleep() {
+        mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(/* value doesn't matter */1);
+    }
+
     private void deviceIsInteractive() {
         mKeyguardUpdateMonitor.dispatchStartedWakingUp();
     }
@@ -1716,7 +1734,9 @@
                     mAuthController, mTelephonyListenerManager,
                     mInteractionJankMonitor, mLatencyTracker, mActiveUnlockConfig,
                     mKeyguardUpdateMonitorLogger, mUiEventLogger, () -> mSessionTracker,
-                    mPowerManager);
+                    mPowerManager, mTrustManager, mSubscriptionManager, mUserManager,
+                    mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
+                    mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager);
             setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 5a26d05..df10dfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -1005,13 +1005,18 @@
         assertEquals(new Size(3, 3), resDelegate.getTopRoundedSize());
         assertEquals(new Size(4, 4), resDelegate.getBottomRoundedSize());
 
-        doReturn(2f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
+                /* roundedTopDrawable */,
+                getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
+                /* roundedBottomDrawable */,
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
         mDisplayInfo.rotation = Surface.ROTATION_270;
 
         mScreenDecorations.onConfigurationChanged(null);
 
-        assertEquals(new Size(6, 6), resDelegate.getTopRoundedSize());
-        assertEquals(new Size(8, 8), resDelegate.getBottomRoundedSize());
+        assertEquals(new Size(4, 4), resDelegate.getTopRoundedSize());
+        assertEquals(new Size(5, 5), resDelegate.getBottomRoundedSize());
     }
 
     @Test
@@ -1288,6 +1293,51 @@
     }
 
     @Test
+    public void testOnDisplayChanged_hwcLayer() {
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+        final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
+        decorationSupport.format = PixelFormat.R_8;
+        doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
+
+        // top cutout
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+
+        mScreenDecorations.start();
+
+        final ScreenDecorHwcLayer hwcLayer = mScreenDecorations.mScreenDecorHwcLayer;
+        spyOn(hwcLayer);
+        doReturn(mDisplay).when(hwcLayer).getDisplay();
+
+        mScreenDecorations.mDisplayListener.onDisplayChanged(1);
+
+        verify(hwcLayer, times(1)).onDisplayChanged(any());
+    }
+
+    @Test
+    public void testOnDisplayChanged_nonHwcLayer() {
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+
+        // top cutout
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+
+        mScreenDecorations.start();
+
+        final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView)
+                mScreenDecorations.getOverlayView(R.id.display_cutout);
+        assertNotNull(cutoutView);
+        spyOn(cutoutView);
+        doReturn(mDisplay).when(cutoutView).getDisplay();
+
+        mScreenDecorations.mDisplayListener.onDisplayChanged(1);
+
+        verify(cutoutView, times(1)).onDisplayChanged(any());
+    }
+
+    @Test
     public void testHasSameProvidersWithNullOverlays() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
index 8fc0489..986e7cd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ViewHierarchyAnimatorTest.kt
@@ -718,7 +718,7 @@
     }
 
     @Test
-    fun animatesViewRemovalFromStartToEnd() {
+    fun animatesViewRemovalFromStartToEnd_viewHasSiblings() {
         setUpRootWithChildren()
 
         val child = rootView.getChildAt(0)
@@ -742,6 +742,35 @@
     }
 
     @Test
+    fun animatesViewRemovalFromStartToEnd_viewHasNoSiblings() {
+        rootView = LinearLayout(mContext)
+        (rootView as LinearLayout).orientation = LinearLayout.HORIZONTAL
+        (rootView as LinearLayout).weightSum = 1f
+
+        val onlyChild = View(mContext)
+        rootView.addView(onlyChild)
+        forceLayout()
+
+        val success = ViewHierarchyAnimator.animateRemoval(
+            onlyChild,
+            destination = ViewHierarchyAnimator.Hotspot.LEFT,
+            interpolator = Interpolators.LINEAR
+        )
+
+        assertTrue(success)
+        assertNotNull(onlyChild.getTag(R.id.tag_animator))
+        checkBounds(onlyChild, l = 0, t = 0, r = 200, b = 100)
+        advanceAnimation(onlyChild, 0.5f)
+        checkBounds(onlyChild, l = 0, t = 0, r = 100, b = 100)
+        advanceAnimation(onlyChild, 1.0f)
+        checkBounds(onlyChild, l = 0, t = 0, r = 0, b = 100)
+        endAnimation(rootView)
+        endAnimation(onlyChild)
+        assertEquals(0, rootView.childCount)
+        assertFalse(onlyChild in rootView.children)
+    }
+
+    @Test
     fun animatesViewRemovalRespectingDestination() {
         // CENTER
         setUpRootWithChildren()
@@ -964,6 +993,60 @@
     }
 
     @Test
+    fun animateRemoval_runnableRunsWhenAnimationEnds() {
+        var runnableRun = false
+        val onAnimationEndRunnable = { runnableRun = true }
+
+        setUpRootWithChildren()
+        forceLayout()
+        val removedView = rootView.getChildAt(0)
+
+        ViewHierarchyAnimator.animateRemoval(
+            removedView,
+            onAnimationEnd = onAnimationEndRunnable
+        )
+        endAnimation(removedView)
+
+        assertEquals(true, runnableRun)
+    }
+
+    @Test
+    fun animateRemoval_runnableDoesNotRunWhenAnimationCancelled() {
+        var runnableRun = false
+        val onAnimationEndRunnable = { runnableRun = true }
+
+        setUpRootWithChildren()
+        forceLayout()
+        val removedView = rootView.getChildAt(0)
+
+        ViewHierarchyAnimator.animateRemoval(
+            removedView,
+            onAnimationEnd = onAnimationEndRunnable
+        )
+        cancelAnimation(removedView)
+
+        assertEquals(false, runnableRun)
+    }
+
+    @Test
+    fun animationRemoval_runnableDoesNotRunWhenOnlyPartwayThroughAnimation() {
+        var runnableRun = false
+        val onAnimationEndRunnable = { runnableRun = true }
+
+        setUpRootWithChildren()
+        forceLayout()
+        val removedView = rootView.getChildAt(0)
+
+        ViewHierarchyAnimator.animateRemoval(
+            removedView,
+            onAnimationEnd = onAnimationEndRunnable
+        )
+        advanceAnimation(removedView, 0.5f)
+
+        assertEquals(false, runnableRun)
+    }
+
+    @Test
     fun cleansUpListenersCorrectly() {
         val firstChild = View(mContext)
         firstChild.layoutParams = LinearLayout.LayoutParams(50 /* width */, 100 /* height */)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 4a5b23c..d52612b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -322,6 +322,13 @@
     }
 
     @Test
+    fun testLayoutParams_hasShowWhenLockedFlag() {
+        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        assertThat((layoutParams.flags and WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) != 0)
+                .isTrue()
+    }
+
+    @Test
     fun testLayoutParams_hasDimbehindWindowFlag() {
         val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
         val lpFlags = layoutParams.flags
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 37bb0c2..0b528a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -117,13 +117,12 @@
     }
 
     @Test
-    fun testFingerprintTrigger_KeyguardVisible_Ripple() {
-        // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
+    fun testFingerprintTrigger_KeyguardShowing_Ripple() {
+        // GIVEN fp exists, keyguard is showing, user doesn't need strong auth
         val fpsLocation = Point(5, 5)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
-        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
 
         // WHEN fingerprint authenticated
@@ -140,39 +139,15 @@
     }
 
     @Test
-    fun testFingerprintTrigger_Dreaming_Ripple() {
-        // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
-        val fpsLocation = Point(5, 5)
-        `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
-        controller.onViewAttached()
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
-        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(true)
-        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
-
-        // WHEN fingerprint authenticated
-        val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
-        verify(keyguardUpdateMonitor).registerCallback(captor.capture())
-        captor.value.onBiometricAuthenticated(
-                0 /* userId */,
-                BiometricSourceType.FINGERPRINT /* type */,
-                false /* isStrongBiometric */)
-
-        // THEN update sensor location and show ripple
-        verify(rippleView).setFingerprintSensorLocation(fpsLocation, 0f)
-        verify(rippleView).startUnlockedRipple(any())
-    }
-
-    @Test
-    fun testFingerprintTrigger_KeyguardNotVisible_NotDreaming_NoRipple() {
+    fun testFingerprintTrigger_KeyguardNotShowing_NoRipple() {
         // GIVEN fp exists & user doesn't need strong auth
         val fpsLocation = Point(5, 5)
         `when`(authController.udfpsLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
 
-        // WHEN keyguard is NOT visible & fingerprint authenticated
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(false)
-        `when`(keyguardUpdateMonitor.isDreaming).thenReturn(false)
+        // WHEN keyguard is NOT showing & fingerprint authenticated
+        `when`(keyguardStateController.isShowing).thenReturn(false)
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
         verify(keyguardUpdateMonitor).registerCallback(captor.capture())
         captor.value.onBiometricAuthenticated(
@@ -186,11 +161,11 @@
 
     @Test
     fun testFingerprintTrigger_StrongAuthRequired_NoRipple() {
-        // GIVEN fp exists & keyguard is visible
+        // GIVEN fp exists & keyguard is showing
         val fpsLocation = Point(5, 5)
         `when`(authController.udfpsLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
 
         // WHEN user needs strong auth & fingerprint authenticated
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(true)
@@ -207,12 +182,12 @@
 
     @Test
     fun testFaceTriggerBypassEnabled_Ripple() {
-        // GIVEN face auth sensor exists, keyguard is visible & strong auth isn't required
+        // GIVEN face auth sensor exists, keyguard is showing & strong auth isn't required
         val faceLocation = Point(5, 5)
         `when`(authController.faceSensorLocation).thenReturn(faceLocation)
         controller.onViewAttached()
 
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
 
         // WHEN bypass is enabled & face authenticated
@@ -299,7 +274,7 @@
         val fpsLocation = Point(5, 5)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
 
         controller.showUnlockRipple(BiometricSourceType.FINGERPRINT)
@@ -317,7 +292,7 @@
         val faceLocation = Point(5, 5)
         `when`(authController.faceSensorLocation).thenReturn(faceLocation)
         controller.onViewAttached()
-        `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
+        `when`(keyguardStateController.isShowing).thenReturn(true)
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
         `when`(authController.isUdfpsFingerDown).thenReturn(true)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 08b1c28..53e8c6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
 
 import static junit.framework.Assert.assertEquals;
 
@@ -681,6 +682,58 @@
     }
 
     @Test
+    public void aodInterruptCancelTimeoutActionWhenFingerUp() throws RemoteException {
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
+
+        // GIVEN AOD interrupt
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
+                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mScreenObserver.onScreenTurnedOn();
+        mFgExecutor.runAllReady();
+        mUdfpsController.onAodInterrupt(0, 0, 0f, 0f);
+        mFgExecutor.runAllReady();
+
+        // Configure UdfpsView to accept the ACTION_UP event
+        when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
+
+        // WHEN ACTION_UP is received
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+        MotionEvent upEvent = MotionEvent.obtain(0, 0, ACTION_UP, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+        mBiometricsExecutor.runAllReady();
+        upEvent.recycle();
+
+        // Configure UdfpsView to accept the ACTION_DOWN event
+        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+
+        // WHEN ACTION_DOWN is received
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        mBiometricsExecutor.runAllReady();
+        downEvent.recycle();
+
+        // WHEN ACTION_MOVE is received
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        mBiometricsExecutor.runAllReady();
+        moveEvent.recycle();
+        mFgExecutor.runAllReady();
+
+        // Configure UdfpsView to accept the finger up event
+        when(mUdfpsView.isDisplayConfigured()).thenReturn(true);
+
+        // WHEN it times out
+        mFgExecutor.advanceClockToNext();
+        mFgExecutor.runAllReady();
+
+        // THEN the display should be unconfigured once. If the timeout action is not
+        // cancelled, the display would be unconfigured twice which would cause two
+        // FP attempts.
+        verify(mUdfpsView, times(1)).unconfigureDisplay();
+    }
+
+    @Test
     public void aodInterruptScreenOff() throws RemoteException {
         // GIVEN screen off
         mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index 434cb48..25bc91f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -96,7 +96,7 @@
     @Mock
     private lateinit var removalPendingStore: PendingRemovalStore
 
-    private lateinit var executor: Executor
+    private lateinit var mainExecutor: Executor
 
     @Captor
     private lateinit var argumentCaptor: ArgumentCaptor<ReceiverData>
@@ -108,11 +108,12 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         testableLooper = TestableLooper.get(this)
-        executor = FakeExecutor(FakeSystemClock())
-        `when`(mockContext.mainExecutor).thenReturn(executor)
+        mainExecutor = FakeExecutor(FakeSystemClock())
+        `when`(mockContext.mainExecutor).thenReturn(mainExecutor)
 
         broadcastDispatcher = TestBroadcastDispatcher(
                 mockContext,
+                mainExecutor,
                 testableLooper.looper,
                 mock(Executor::class.java),
                 mock(DumpManager::class.java),
@@ -148,9 +149,9 @@
 
     @Test
     fun testAddingReceiverToCorrectUBR_executor() {
-        broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, executor, user0)
+        broadcastDispatcher.registerReceiver(broadcastReceiver, intentFilter, mainExecutor, user0)
         broadcastDispatcher.registerReceiver(
-                broadcastReceiverOther, intentFilterOther, executor, user1)
+                broadcastReceiverOther, intentFilterOther, mainExecutor, user1)
 
         testableLooper.processAllMessages()
 
@@ -427,8 +428,9 @@
 
     private class TestBroadcastDispatcher(
         context: Context,
-        bgLooper: Looper,
-        executor: Executor,
+        mainExecutor: Executor,
+        backgroundRunningLooper: Looper,
+        backgroundRunningExecutor: Executor,
         dumpManager: DumpManager,
         logger: BroadcastDispatcherLogger,
         userTracker: UserTracker,
@@ -436,8 +438,9 @@
         var mockUBRMap: Map<Int, UserBroadcastDispatcher>
     ) : BroadcastDispatcher(
         context,
-        bgLooper,
-        executor,
+        mainExecutor,
+        backgroundRunningLooper,
+        backgroundRunningExecutor,
         dumpManager,
         logger,
         userTracker,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
index d70d6fc..588edb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/TypeClassifierTest.java
@@ -19,6 +19,7 @@
 import static com.android.systemui.classifier.Classifier.BOUNCER_UNLOCK;
 import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
 import static com.android.systemui.classifier.Classifier.LEFT_AFFORDANCE;
+import static com.android.systemui.classifier.Classifier.MEDIA_SEEKBAR;
 import static com.android.systemui.classifier.Classifier.NOTIFICATION_DISMISS;
 import static com.android.systemui.classifier.Classifier.NOTIFICATION_DRAG_DOWN;
 import static com.android.systemui.classifier.Classifier.PULSE_EXPAND;
@@ -406,4 +407,46 @@
         when(mDataProvider.isRight()).thenReturn(true);
         assertThat(mClassifier.classifyGesture(QS_SWIPE_NESTED, 0.5, 0).isFalse()).isTrue();
     }
+
+    @Test
+    public void testPass_MediaSeekbar() {
+        when(mDataProvider.isVertical()).thenReturn(false);
+
+        when(mDataProvider.isUp()).thenReturn(false);  // up and right should cause no effect.
+        when(mDataProvider.isRight()).thenReturn(false);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isFalse();
+
+        when(mDataProvider.isUp()).thenReturn(true);
+        when(mDataProvider.isRight()).thenReturn(false);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isFalse();
+
+        when(mDataProvider.isUp()).thenReturn(false);
+        when(mDataProvider.isRight()).thenReturn(true);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isFalse();
+
+        when(mDataProvider.isUp()).thenReturn(true);
+        when(mDataProvider.isRight()).thenReturn(true);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isFalse();
+    }
+
+    @Test
+    public void testFalse_MediaSeekbar() {
+        when(mDataProvider.isVertical()).thenReturn(true);
+
+        when(mDataProvider.isUp()).thenReturn(false);  // up and right should cause no effect.
+        when(mDataProvider.isRight()).thenReturn(false);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isTrue();
+
+        when(mDataProvider.isUp()).thenReturn(true);
+        when(mDataProvider.isRight()).thenReturn(false);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isTrue();
+
+        when(mDataProvider.isUp()).thenReturn(false);
+        when(mDataProvider.isRight()).thenReturn(true);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isTrue();
+
+        when(mDataProvider.isUp()).thenReturn(true);
+        when(mDataProvider.isRight()).thenReturn(true);
+        assertThat(mClassifier.classifyGesture(MEDIA_SEEKBAR, 0.5, 0).isFalse()).isTrue();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
index 08fe7c4..2a4c0eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
@@ -16,13 +16,14 @@
 
 package com.android.systemui.clipboardoverlay;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.net.Uri;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import android.text.SpannableString;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -129,6 +130,18 @@
         assertEquals("image/png", target.getType());
     }
 
+    @Test
+    public void test_getShareIntent_spannableText() {
+        ClipData clipData = ClipData.newPlainText("Test", new SpannableString("Test Item"));
+        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+        Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
+        assertEquals("Test Item", target.getStringExtra(Intent.EXTRA_TEXT));
+        assertEquals("text/plain", target.getType());
+    }
+
     // Assert that the given flags are set
     private void assertFlags(Intent intent, int flags) {
         assertTrue((intent.getFlags() & flags) == flags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
index 93a1868..f933361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -24,11 +24,12 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.R as InternalR
 import com.android.systemui.R as SystemUIR
-import com.android.systemui.SysuiTestCase
 import com.android.systemui.tests.R
+import com.android.systemui.SysuiTestCase
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
+
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
@@ -101,11 +102,14 @@
         assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
         assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
 
-        roundedCornerResDelegate.physicalPixelDisplaySizeRatio = 2f
+        setupResources(radius = 100,
+                roundedTopDrawable = getTestsDrawable(R.drawable.rounded4px),
+                roundedBottomDrawable = getTestsDrawable(R.drawable.rounded5px))
+
         roundedCornerResDelegate.updateDisplayUniqueId(null, 1)
 
-        assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize)
-        assertEquals(Size(8, 8), roundedCornerResDelegate.bottomRoundedSize)
+        assertEquals(Size(4, 4), roundedCornerResDelegate.topRoundedSize)
+        assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
     }
 
     @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 6436981..781dc15 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -144,6 +144,12 @@
         mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
         clearInvocations(mMachine);
 
+        ArgumentCaptor<Boolean> boolCaptor = ArgumentCaptor.forClass(Boolean.class);
+        doAnswer(invocation ->
+                when(mHost.isPulsePending()).thenReturn(boolCaptor.getValue())
+        ).when(mHost).setPulsePending(boolCaptor.capture());
+
+        when(mHost.isPulsingBlocked()).thenReturn(false);
         mProximitySensor.setLastEvent(new ThresholdSensorEvent(true, 1));
         captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
         mProximitySensor.alertListeners();
@@ -160,6 +166,29 @@
     }
 
     @Test
+    public void testOnNotification_noPulseIfPulseIsNotPendingAnymore() {
+        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
+        ArgumentCaptor<DozeHost.Callback> captor = ArgumentCaptor.forClass(DozeHost.Callback.class);
+        doAnswer(invocation -> null).when(mHost).addCallback(captor.capture());
+
+        mTriggers.transitionTo(UNINITIALIZED, DozeMachine.State.INITIALIZED);
+        mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+        clearInvocations(mMachine);
+        when(mHost.isPulsingBlocked()).thenReturn(false);
+
+        // GIVEN pulsePending = false
+        when(mHost.isPulsePending()).thenReturn(false);
+
+        // WHEN prox check returns FAR
+        mProximitySensor.setLastEvent(new ThresholdSensorEvent(false, 2));
+        captor.getValue().onNotificationAlerted(null /* pulseSuppressedListener */);
+        mProximitySensor.alertListeners();
+
+        // THEN don't request pulse because the pending pulse was abandoned early
+        verify(mMachine, never()).requestPulse(anyInt());
+    }
+
+    @Test
     public void testTransitionTo_disablesAndEnablesTouchSensors() {
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
@@ -237,6 +266,11 @@
         when(mSessionTracker.getSessionId(StatusBarManager.SESSION_KEYGUARD))
                 .thenReturn(keyguardSessionId);
 
+        ArgumentCaptor<Boolean> boolCaptor = ArgumentCaptor.forClass(Boolean.class);
+        doAnswer(invocation ->
+                when(mHost.isPulsePending()).thenReturn(boolCaptor.getValue())
+        ).when(mHost).setPulsePending(boolCaptor.capture());
+
         // WHEN quick pick up is triggered
         mTriggers.onSensor(DozeLog.REASON_SENSOR_QUICK_PICKUP, 100, 100, null);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
index 2448f1a..849ac5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
@@ -297,10 +297,10 @@
     }
 
     /**
-     * Ensures margin is applied
+     * Ensures default margin is applied
      */
     @Test
-    public void testMargin() {
+    public void testDefaultMargin() {
         final int margin = 5;
         final ComplicationLayoutEngine engine =
                 new ComplicationLayoutEngine(mLayout, margin, mTouchSession, 0, 0);
@@ -373,6 +373,74 @@
     }
 
     /**
+     * Ensures complication margin is applied
+     */
+    @Test
+    public void testComplicationMargin() {
+        final int defaultMargin = 5;
+        final int complicationMargin = 10;
+        final ComplicationLayoutEngine engine =
+                new ComplicationLayoutEngine(mLayout, defaultMargin, mTouchSession, 0, 0);
+
+        final ViewInfo firstViewInfo = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_TOP
+                                | ComplicationLayoutParams.POSITION_END,
+                        ComplicationLayoutParams.DIRECTION_DOWN,
+                        0,
+                        complicationMargin),
+                Complication.CATEGORY_STANDARD,
+                mLayout);
+
+        addComplication(engine, firstViewInfo);
+
+        final ViewInfo secondViewInfo = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_TOP
+                                | ComplicationLayoutParams.POSITION_END,
+                        ComplicationLayoutParams.DIRECTION_START,
+                        0),
+                Complication.CATEGORY_SYSTEM,
+                mLayout);
+
+        addComplication(engine, secondViewInfo);
+
+        firstViewInfo.clearInvocations();
+        secondViewInfo.clearInvocations();
+
+        final ViewInfo thirdViewInfo = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_TOP
+                                | ComplicationLayoutParams.POSITION_END,
+                        ComplicationLayoutParams.DIRECTION_START,
+                        1),
+                Complication.CATEGORY_SYSTEM,
+                mLayout);
+
+        addComplication(engine, thirdViewInfo);
+
+        // The first added view should now be underneath the second view.
+        verifyChange(firstViewInfo, false, lp -> {
+            assertThat(lp.topToBottom == thirdViewInfo.view.getId()).isTrue();
+            assertThat(lp.endToEnd == ConstraintLayout.LayoutParams.PARENT_ID).isTrue();
+            assertThat(lp.topMargin).isEqualTo(complicationMargin);
+        });
+
+        // The second view should be in underneath the third view.
+        verifyChange(secondViewInfo, false, lp -> {
+            assertThat(lp.endToStart == thirdViewInfo.view.getId()).isTrue();
+            assertThat(lp.topToTop == ConstraintLayout.LayoutParams.PARENT_ID).isTrue();
+            assertThat(lp.getMarginEnd()).isEqualTo(defaultMargin);
+        });
+    }
+
+    /**
      * Ensures layout in a particular position updates.
      */
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java
index 967b30d..cb7e47b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java
@@ -97,6 +97,35 @@
     }
 
     /**
+     * Ensures unspecified margin uses default.
+     */
+    @Test
+    public void testUnspecifiedMarginUsesDefault() {
+        final ComplicationLayoutParams params = new ComplicationLayoutParams(
+                100,
+                100,
+                ComplicationLayoutParams.POSITION_TOP,
+                ComplicationLayoutParams.DIRECTION_DOWN,
+                3);
+        assertThat(params.getMargin(10) == 10).isTrue();
+    }
+
+    /**
+     * Ensures specified margin is used instead of default.
+     */
+    @Test
+    public void testSpecifiedMargin() {
+        final ComplicationLayoutParams params = new ComplicationLayoutParams(
+                100,
+                100,
+                ComplicationLayoutParams.POSITION_TOP,
+                ComplicationLayoutParams.DIRECTION_DOWN,
+                3,
+                10);
+        assertThat(params.getMargin(5) == 10).isTrue();
+    }
+
+    /**
      * Ensures ComplicationLayoutParams is properly duplicated on copy construction.
      */
     @Test
@@ -106,12 +135,36 @@
                 100,
                 ComplicationLayoutParams.POSITION_TOP,
                 ComplicationLayoutParams.DIRECTION_DOWN,
+                3,
+                10);
+        final ComplicationLayoutParams copy = new ComplicationLayoutParams(params);
+
+        assertThat(copy.getDirection() == params.getDirection()).isTrue();
+        assertThat(copy.getPosition() == params.getPosition()).isTrue();
+        assertThat(copy.getWeight() == params.getWeight()).isTrue();
+        assertThat(copy.getMargin(0) == params.getMargin(1)).isTrue();
+        assertThat(copy.height == params.height).isTrue();
+        assertThat(copy.width == params.width).isTrue();
+    }
+
+    /**
+     * Ensures ComplicationLayoutParams is properly duplicated on copy construction with unspecified
+     * margin.
+     */
+    @Test
+    public void testCopyConstructionWithUnspecifiedMargin() {
+        final ComplicationLayoutParams params = new ComplicationLayoutParams(
+                100,
+                100,
+                ComplicationLayoutParams.POSITION_TOP,
+                ComplicationLayoutParams.DIRECTION_DOWN,
                 3);
         final ComplicationLayoutParams copy = new ComplicationLayoutParams(params);
 
         assertThat(copy.getDirection() == params.getDirection()).isTrue();
         assertThat(copy.getPosition() == params.getPosition()).isTrue();
         assertThat(copy.getWeight() == params.getWeight()).isTrue();
+        assertThat(copy.getMargin(1) == params.getMargin(1)).isTrue();
         assertThat(copy.height == params.height).isTrue();
         assertThat(copy.width == params.width).isTrue();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index 04ff7ae..db6082d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -29,9 +29,12 @@
 
 import android.content.Context;
 import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.widget.ImageView;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.controls.ControlsServiceInfo;
 import com.android.systemui.controls.controller.ControlsController;
@@ -40,6 +43,7 @@
 import com.android.systemui.controls.management.ControlsListingController;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dreams.complication.dagger.DreamHomeControlsComplicationComponent;
+import com.android.systemui.plugins.ActivityStarter;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -79,6 +83,15 @@
     @Captor
     private ArgumentCaptor<ControlsListingController.ControlsListingCallback> mCallbackCaptor;
 
+    @Mock
+    private ImageView mView;
+
+    @Mock
+    private ActivityStarter mActivityStarter;
+
+    @Mock
+    UiEventLogger mUiEventLogger;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
@@ -151,6 +164,30 @@
         verify(mDreamOverlayStateController).addComplication(mComplication);
     }
 
+    /**
+     * Ensures clicking home controls chip logs UiEvent.
+     */
+    @Test
+    public void testClick_logsUiEvent() {
+        final DreamHomeControlsComplication.DreamHomeControlsChipViewController viewController =
+                new DreamHomeControlsComplication.DreamHomeControlsChipViewController(
+                        mView,
+                        mActivityStarter,
+                        mContext,
+                        mControlsComponent,
+                        mUiEventLogger);
+        viewController.onViewAttached();
+
+        final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mView).setOnClickListener(clickListenerCaptor.capture());
+
+        clickListenerCaptor.getValue().onClick(mView);
+        verify(mUiEventLogger).log(
+                DreamHomeControlsComplication.DreamHomeControlsChipViewController
+                        .DreamOverlayEvent.DREAM_HOME_CONTROLS_TAPPED);
+    }
+
     private void setHaveFavorites(boolean value) {
         final List<StructureInfo> favorites = mock(List.class);
         when(favorites.isEmpty()).thenReturn(!value);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index 4511193..20a82c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -21,15 +21,10 @@
 import android.content.pm.PackageManager.NameNotFoundException
 import android.content.res.Resources
 import android.test.suitebuilder.annotation.SmallTest
-import com.android.internal.statusbar.IStatusBarService
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
-import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.util.DeviceConfigProxyFake
 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.mockito.nullable
 import com.android.systemui.util.mockito.withArgCaptor
@@ -46,18 +41,16 @@
 import org.mockito.Mock
 import org.mockito.Mockito.anyBoolean
 import org.mockito.Mockito.anyString
-import org.mockito.Mockito.atLeastOnce
 import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 /**
- * NOTE: This test is for the version of FeatureFlagManager in src-release, which should not allow
- * overriding, and should never return any value other than the one provided as the default.
+ * NOTE: This test is for the version of FeatureFlagManager in src-debug, which allows overriding
+ * the default.
  */
 @SmallTest
 class FeatureFlagsDebugTest : SysuiTestCase() {
@@ -68,10 +61,8 @@
     @Mock private lateinit var secureSettings: SecureSettings
     @Mock private lateinit var systemProperties: SystemPropertiesHelper
     @Mock private lateinit var resources: Resources
-    @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var commandRegistry: CommandRegistry
-    @Mock private lateinit var barService: IStatusBarService
-    @Mock private lateinit var pw: PrintWriter
+    @Mock private lateinit var restarter: Restarter
     private val flagMap = mutableMapOf<Int, Flag<*>>()
     private lateinit var broadcastReceiver: BroadcastReceiver
     private lateinit var clearCacheAction: Consumer<Int>
@@ -92,12 +83,10 @@
             secureSettings,
             systemProperties,
             resources,
-            dumpManager,
             deviceConfig,
             serverFlagReader,
             flagMap,
-            commandRegistry,
-            barService
+            restarter
         )
         verify(flagManager).onSettingsChangedAction = any()
         broadcastReceiver = withArgCaptor {
@@ -366,53 +355,6 @@
     }
 
     @Test
-    fun statusBarCommand_IsRegistered() {
-        verify(commandRegistry).registerCommand(anyString(), any())
-    }
-
-    @Test
-    fun noOpCommand() {
-        val cmd = captureCommand()
-
-        cmd.execute(pw, ArrayList())
-        verify(pw, atLeastOnce()).println()
-        verify(flagManager).readFlagValue<Boolean>(eq(1), any())
-        verifyZeroInteractions(secureSettings)
-    }
-
-    @Test
-    fun readFlagCommand() {
-        addFlag(UnreleasedFlag(1))
-        val cmd = captureCommand()
-        cmd.execute(pw, listOf("1"))
-        verify(flagManager).readFlagValue<Boolean>(eq(1), any())
-    }
-
-    @Test
-    fun setFlagCommand() {
-        addFlag(UnreleasedFlag(1))
-        val cmd = captureCommand()
-        cmd.execute(pw, listOf("1", "on"))
-        verifyPutData(1, "{\"type\":\"boolean\",\"value\":true}")
-    }
-
-    @Test
-    fun toggleFlagCommand() {
-        addFlag(ReleasedFlag(1))
-        val cmd = captureCommand()
-        cmd.execute(pw, listOf("1", "toggle"))
-        verifyPutData(1, "{\"type\":\"boolean\",\"value\":false}", 2)
-    }
-
-    @Test
-    fun eraseFlagCommand() {
-        addFlag(ReleasedFlag(1))
-        val cmd = captureCommand()
-        cmd.execute(pw, listOf("1", "erase"))
-        verify(secureSettings).putStringForUser(eq("key-1"), eq(""), anyInt())
-    }
-
-    @Test
     fun dumpFormat() {
         val flag1 = ReleasedFlag(1)
         val flag2 = ResourceBooleanFlag(2, 1002)
@@ -471,13 +413,6 @@
         return flag
     }
 
-    private fun captureCommand(): Command {
-        val captor = argumentCaptor<Function0<Command>>()
-        verify(commandRegistry).registerCommand(anyString(), capture(captor))
-
-        return captor.value.invoke()
-    }
-
     private fun dumpToString(): String {
         val sw = StringWriter()
         val pw = PrintWriter(sw)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
index e94b520..575c142 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsReleaseTest.kt
@@ -19,17 +19,12 @@
 import android.content.res.Resources
 import android.test.suitebuilder.annotation.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.dump.DumpManager
 import com.android.systemui.util.DeviceConfigProxyFake
-import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
-import org.junit.After
 import org.junit.Assert.assertThrows
 import org.junit.Before
 import org.junit.Test
 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
 
@@ -43,7 +38,6 @@
 
     @Mock private lateinit var mResources: Resources
     @Mock private lateinit var mSystemProperties: SystemPropertiesHelper
-    @Mock private lateinit var mDumpManager: DumpManager
     private val serverFlagReader = ServerFlagReaderFake()
 
     private val deviceConfig = DeviceConfigProxyFake()
@@ -55,15 +49,7 @@
             mResources,
             mSystemProperties,
             deviceConfig,
-            serverFlagReader,
-            mDumpManager)
-    }
-
-    @After
-    fun onFinished() {
-        // The dump manager should be registered with even for the release version, but that's it.
-        verify(mDumpManager).registerDumpable(any(), any())
-        verifyNoMoreInteractions(mDumpManager)
+            serverFlagReader)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
new file mode 100644
index 0000000..4c61138
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FlagCommandTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.flags
+
+import android.test.suitebuilder.annotation.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import java.io.PrintWriter
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class FlagCommandTest : SysuiTestCase() {
+
+    @Mock private lateinit var featureFlags: FeatureFlagsDebug
+    @Mock private lateinit var pw: PrintWriter
+    private val flagMap = mutableMapOf<Int, Flag<*>>()
+    private val flagA = UnreleasedFlag(500)
+    private val flagB = ReleasedFlag(501)
+
+    private lateinit var cmd: FlagCommand
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+
+        whenever(featureFlags.isEnabled(any(UnreleasedFlag::class.java))).thenReturn(false)
+        whenever(featureFlags.isEnabled(any(ReleasedFlag::class.java))).thenReturn(true)
+        flagMap.put(flagA.id, flagA)
+        flagMap.put(flagB.id, flagB)
+
+        cmd = FlagCommand(featureFlags, flagMap)
+    }
+
+    @Test
+    fun noOpCommand() {
+        cmd.execute(pw, ArrayList())
+        Mockito.verify(pw, Mockito.atLeastOnce()).println()
+        Mockito.verify(featureFlags).isEnabled(flagA)
+        Mockito.verify(featureFlags).isEnabled(flagB)
+    }
+
+    @Test
+    fun readFlagCommand() {
+        cmd.execute(pw, listOf(flagA.id.toString()))
+        Mockito.verify(featureFlags).isEnabled(flagA)
+    }
+
+    @Test
+    fun setFlagCommand() {
+        cmd.execute(pw, listOf(flagB.id.toString(), "on"))
+        Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, true)
+    }
+
+    @Test
+    fun toggleFlagCommand() {
+        cmd.execute(pw, listOf(flagB.id.toString(), "toggle"))
+        Mockito.verify(featureFlags).setBooleanFlagInternal(flagB, false)
+    }
+
+    @Test
+    fun eraseFlagCommand() {
+        cmd.execute(pw, listOf(flagA.id.toString(), "erase"))
+        Mockito.verify(featureFlags).eraseFlag(flagA)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index b42b769..8b1554c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -48,6 +48,7 @@
 import android.window.OnBackInvokedCallback;
 import android.window.OnBackInvokedDispatcher;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
@@ -234,6 +235,11 @@
         verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(any());
     }
 
+    /**
+     * This specific test case appears to be flaky.
+     * b/249136797 tracks the task of root-causing and fixing it.
+     */
+    @FlakyTest
     @Test
     public void testPredictiveBackInvocationDismissesDialog() {
         mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
index d418836..7f55d38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java
@@ -49,6 +49,7 @@
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BooleanSupplier;
 
@@ -148,8 +149,12 @@
         return false;
     }
 
-    private static void executeShellCommand(String cmd) {
-        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(cmd);
+    private void executeShellCommand(String cmd) {
+        try {
+            runShellCommand(cmd);
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
     }
 
     /**
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 ba1e168..7a15680 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
@@ -23,6 +23,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -33,7 +34,6 @@
 import org.junit.runners.JUnit4
 import org.mockito.Mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -116,6 +116,7 @@
         val job = underTest.isKeyguardShowing.onEach { latest = it }.launchIn(this)
 
         assertThat(latest).isFalse()
+        assertThat(underTest.isKeyguardShowing()).isFalse()
 
         val captor = argumentCaptor<KeyguardStateController.Callback>()
         verify(keyguardStateController).addCallback(captor.capture())
@@ -123,10 +124,12 @@
         whenever(keyguardStateController.isShowing).thenReturn(true)
         captor.value.onKeyguardShowingChanged()
         assertThat(latest).isTrue()
+        assertThat(underTest.isKeyguardShowing()).isTrue()
 
         whenever(keyguardStateController.isShowing).thenReturn(false)
         captor.value.onKeyguardShowingChanged()
         assertThat(latest).isFalse()
+        assertThat(underTest.isKeyguardShowing()).isFalse()
 
         job.cancel()
     }
@@ -150,6 +153,21 @@
     }
 
     @Test
+    fun `isDozing - starts with correct initial value for isDozing`() = runBlockingTest {
+        var latest: Boolean? = null
+
+        whenever(statusBarStateController.isDozing).thenReturn(true)
+        var job = underTest.isDozing.onEach { latest = it }.launchIn(this)
+        assertThat(latest).isTrue()
+        job.cancel()
+
+        whenever(statusBarStateController.isDozing).thenReturn(false)
+        job = underTest.isDozing.onEach { latest = it }.launchIn(this)
+        assertThat(latest).isFalse()
+        job.cancel()
+    }
+
+    @Test
     fun dozeAmount() = runBlockingTest {
         val values = mutableListOf<Float>()
         val job = underTest.dozeAmount.onEach(values::add).launchIn(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
index d4fba41..329c4db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QrCodeScannerKeyguardQuickAffordanceConfigTest.kt
@@ -138,7 +138,7 @@
         assertThat(latest).isInstanceOf(KeyguardQuickAffordanceConfig.State.Visible::class.java)
         val visibleState = latest as KeyguardQuickAffordanceConfig.State.Visible
         assertThat(visibleState.icon).isNotNull()
-        assertThat(visibleState.contentDescriptionResourceId).isNotNull()
+        assertThat(visibleState.icon.contentDescription).isNotNull()
     }
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
index 5a3a78e..0a4478f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt
@@ -21,9 +21,11 @@
 import android.service.quickaccesswallet.GetWalletCardsResponse
 import android.service.quickaccesswallet.QuickAccessWalletClient
 import androidx.test.filters.SmallTest
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
@@ -69,8 +71,16 @@
         val job = underTest.state.onEach { latest = it }.launchIn(this)
 
         val visibleModel = latest as KeyguardQuickAffordanceConfig.State.Visible
-        assertThat(visibleModel.icon).isEqualTo(ContainedDrawable.WithDrawable(ICON))
-        assertThat(visibleModel.contentDescriptionResourceId).isNotNull()
+        assertThat(visibleModel.icon)
+            .isEqualTo(
+                Icon.Loaded(
+                    drawable = ICON,
+                    contentDescription =
+                        ContentDescription.Resource(
+                            res = R.string.accessibility_wallet_button,
+                        ),
+                )
+            )
         job.cancel()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index c5e828e..b6d7559 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -21,7 +21,8 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
@@ -34,6 +35,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import kotlinx.coroutines.test.runBlockingTest
 import org.junit.Before
 import org.junit.Test
@@ -46,7 +48,6 @@
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
 @SmallTest
@@ -55,7 +56,15 @@
 
     companion object {
         private val INTENT = Intent("some.intent.action")
-        private val DRAWABLE = mock<ContainedDrawable>()
+        private val DRAWABLE =
+            mock<Icon> {
+                whenever(this.contentDescription)
+                    .thenReturn(
+                        ContentDescription.Resource(
+                            res = CONTENT_DESCRIPTION_RESOURCE_ID,
+                        )
+                    )
+            }
         private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337
 
         @Parameters(
@@ -236,7 +245,6 @@
             state =
                 KeyguardQuickAffordanceConfig.State.Visible(
                     icon = DRAWABLE,
-                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
                 )
         )
         homeControls.onClickedResult =
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 19d8412..1dd919a 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
@@ -19,7 +19,8 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
@@ -32,6 +33,7 @@
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -101,7 +103,6 @@
         homeControls.setState(
             KeyguardQuickAffordanceConfig.State.Visible(
                 icon = ICON,
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
             )
         )
 
@@ -120,8 +121,8 @@
         val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
         assertThat(visibleModel.configKey).isEqualTo(configKey)
         assertThat(visibleModel.icon).isEqualTo(ICON)
-        assertThat(visibleModel.contentDescriptionResourceId)
-            .isEqualTo(CONTENT_DESCRIPTION_RESOURCE_ID)
+        assertThat(visibleModel.icon.contentDescription)
+            .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
         job.cancel()
     }
 
@@ -131,7 +132,6 @@
         quickAccessWallet.setState(
             KeyguardQuickAffordanceConfig.State.Visible(
                 icon = ICON,
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
             )
         )
 
@@ -150,8 +150,8 @@
         val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
         assertThat(visibleModel.configKey).isEqualTo(configKey)
         assertThat(visibleModel.icon).isEqualTo(ICON)
-        assertThat(visibleModel.contentDescriptionResourceId)
-            .isEqualTo(CONTENT_DESCRIPTION_RESOURCE_ID)
+        assertThat(visibleModel.icon.contentDescription)
+            .isEqualTo(ContentDescription.Resource(res = CONTENT_DESCRIPTION_RESOURCE_ID))
         job.cancel()
     }
 
@@ -161,7 +161,6 @@
         homeControls.setState(
             KeyguardQuickAffordanceConfig.State.Visible(
                 icon = ICON,
-                contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
             )
         )
 
@@ -182,7 +181,6 @@
             homeControls.setState(
                 KeyguardQuickAffordanceConfig.State.Visible(
                     icon = ICON,
-                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
                 )
             )
 
@@ -197,7 +195,14 @@
         }
 
     companion object {
-        private val ICON: ContainedDrawable = mock()
+        private val ICON: Icon = mock {
+            whenever(this.contentDescription)
+                .thenReturn(
+                    ContentDescription.Resource(
+                        res = CONTENT_DESCRIPTION_RESOURCE_ID,
+                    )
+                )
+        }
         private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337
     }
 }
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 c612091..96544e7 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
@@ -21,7 +21,7 @@
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.containeddrawable.ContainedDrawable
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.doze.util.BurnInHelperWrapper
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
@@ -505,7 +505,6 @@
                 }
                 KeyguardQuickAffordanceConfig.State.Visible(
                     icon = testConfig.icon ?: error("Icon is unexpectedly null!"),
-                    contentDescriptionResourceId = CONTENT_DESCRIPTION_RESOURCE_ID,
                 )
             } else {
                 KeyguardQuickAffordanceConfig.State.Hidden
@@ -543,7 +542,7 @@
     private data class TestConfig(
         val isVisible: Boolean,
         val isClickable: Boolean = false,
-        val icon: ContainedDrawable? = null,
+        val icon: Icon? = null,
         val canShowWhileLocked: Boolean = false,
         val intent: Intent? = null,
     ) {
@@ -555,6 +554,5 @@
     companion object {
         private const val DEFAULT_BURN_IN_OFFSET = 5
         private const val RETURNED_BURN_IN_OFFSET = 3
-        private const val CONTENT_DESCRIPTION_RESOURCE_ID = 1337
     }
 }
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 e3e3b74..5ad3542 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -30,7 +30,6 @@
 import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
-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
@@ -46,7 +45,6 @@
 import org.mockito.Mock
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
@@ -73,10 +71,6 @@
     @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
@@ -282,46 +276,6 @@
         verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
     }
 
-    @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,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 82aa612..5973340 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -26,13 +26,13 @@
 import androidx.arch.core.executor.ArchTaskExecutor
 import androidx.arch.core.executor.TaskExecutor
 import androidx.test.filters.SmallTest
-
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.Classifier
+import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.concurrency.FakeRepeatableExecutor
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
-
 import org.junit.After
 import org.junit.Before
 import org.junit.Ignore
@@ -47,8 +47,8 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -70,6 +70,8 @@
     }
     @Mock private lateinit var mockController: MediaController
     @Mock private lateinit var mockTransport: MediaController.TransportControls
+    @Mock private lateinit var falsingManager: FalsingManager
+    @Mock private lateinit var mockBar: SeekBar
     private val token1 = MediaSession.Token(1, null)
     private val token2 = MediaSession.Token(2, null)
 
@@ -78,9 +80,10 @@
     @Before
     fun setUp() {
         fakeExecutor = FakeExecutor(FakeSystemClock())
-        viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor))
+        viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor), falsingManager)
         viewModel.logSeek = { }
         whenever(mockController.sessionToken).thenReturn(token1)
+        whenever(mockBar.context).thenReturn(context)
 
         // LiveData to run synchronously
         ArchTaskExecutor.getInstance().setDelegate(taskExecutor)
@@ -454,6 +457,25 @@
     }
 
     @Test
+    fun onFalseTapOrTouch() {
+        whenever(mockController.getTransportControls()).thenReturn(mockTransport)
+        whenever(falsingManager.isFalseTouch(Classifier.MEDIA_SEEKBAR)).thenReturn(true)
+        whenever(falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)).thenReturn(true)
+        viewModel.updateController(mockController)
+        val pos = 169
+
+        viewModel.attachTouchHandlers(mockBar)
+        with(viewModel.seekBarListener) {
+            onStartTrackingTouch(mockBar)
+            onProgressChanged(mockBar, pos, true)
+            onStopTrackingTouch(mockBar)
+        }
+
+        // THEN transport controls should not be used
+        verify(mockTransport, never()).seekTo(pos.toLong())
+    }
+
+    @Test
     fun queuePollTaskWhenPlaying() {
         // GIVEN that the track is playing
         val state = PlaybackState.Builder().run {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 2a13053..d828193 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -64,6 +64,7 @@
                 context,
                 FakeExecutor(FakeSystemClock()),
             )
+        mediaTttCommandLineHelper.start()
     }
 
     @Test(expected = IllegalStateException::class)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
index 37f6434..7c83cb7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttUtilsTest.kt
@@ -19,9 +19,7 @@
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
-import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
-import com.android.internal.widget.CachingIconView
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.util.mockito.any
@@ -90,48 +88,6 @@
         assertThat(iconInfo.drawable).isEqualTo(appIconFromPackageName)
         assertThat(iconInfo.contentDescription).isEqualTo(APP_NAME)
     }
-
-    @Test
-    fun setIcon_viewHasIconAndContentDescription() {
-        val view = CachingIconView(context)
-        val icon = context.getDrawable(R.drawable.ic_celebration)!!
-        val contentDescription = "Happy birthday!"
-
-        MediaTttUtils.setIcon(view, icon, contentDescription)
-
-        assertThat(view.drawable).isEqualTo(icon)
-        assertThat(view.contentDescription).isEqualTo(contentDescription)
-    }
-
-    @Test
-    fun setIcon_iconSizeNull_viewSizeDoesNotChange() {
-        val view = CachingIconView(context)
-        val size = 456
-        view.layoutParams = FrameLayout.LayoutParams(size, size)
-
-        MediaTttUtils.setIcon(view, context.getDrawable(R.drawable.ic_cake)!!, "desc")
-
-        assertThat(view.layoutParams.width).isEqualTo(size)
-        assertThat(view.layoutParams.height).isEqualTo(size)
-    }
-
-    @Test
-    fun setIcon_iconSizeProvided_viewSizeUpdates() {
-        val view = CachingIconView(context)
-        val size = 456
-        view.layoutParams = FrameLayout.LayoutParams(size, size)
-
-        val newSize = 40
-        MediaTttUtils.setIcon(
-            view,
-            context.getDrawable(R.drawable.ic_cake)!!,
-            "desc",
-            iconSize = newSize
-        )
-
-        assertThat(view.layoutParams.width).isEqualTo(newSize)
-        assertThat(view.layoutParams.height).isEqualTo(newSize)
-    }
 }
 
 private const val PACKAGE_NAME = "com.android.systemui"
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 d41ad48..9577274 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,6 +41,7 @@
 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
@@ -71,6 +72,8 @@
     @Mock
     private lateinit var powerManager: PowerManager
     @Mock
+    private lateinit var viewUtil: ViewUtil
+    @Mock
     private lateinit var windowManager: WindowManager
     @Mock
     private lateinit var commandQueue: CommandQueue
@@ -104,8 +107,10 @@
             configurationController,
             powerManager,
             Handler.getMain(),
-            receiverUiEventLogger
+            receiverUiEventLogger,
+            viewUtil,
         )
+        controllerReceiver.start()
 
         val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
         verify(commandQueue).addCallback(callbackCaptor.capture())
@@ -212,35 +217,27 @@
     }
 
     @Test
-    fun updateView_isAppIcon_usesAppIconSize() {
+    fun updateView_isAppIcon_usesAppIconPadding() {
         controllerReceiver.displayView(getChipReceiverInfo(packageName = PACKAGE_NAME))
+
         val chipView = getChipView()
-
-        chipView.measure(
-            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
-            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
-        )
-
-        val expectedSize =
-            context.resources.getDimensionPixelSize(R.dimen.media_ttt_icon_size_receiver)
-        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
-        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+        assertThat(chipView.getAppIconView().paddingLeft).isEqualTo(0)
+        assertThat(chipView.getAppIconView().paddingRight).isEqualTo(0)
+        assertThat(chipView.getAppIconView().paddingTop).isEqualTo(0)
+        assertThat(chipView.getAppIconView().paddingBottom).isEqualTo(0)
     }
 
     @Test
-    fun updateView_notAppIcon_usesGenericIconSize() {
+    fun updateView_notAppIcon_usesGenericIconPadding() {
         controllerReceiver.displayView(getChipReceiverInfo(packageName = null))
+
         val chipView = getChipView()
-
-        chipView.measure(
-            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
-            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
-        )
-
-        val expectedSize =
-            context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_size_receiver)
-        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(expectedSize)
-        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(expectedSize)
+        val expectedPadding =
+            context.resources.getDimensionPixelSize(R.dimen.media_ttt_generic_icon_padding)
+        assertThat(chipView.getAppIconView().paddingLeft).isEqualTo(expectedPadding)
+        assertThat(chipView.getAppIconView().paddingRight).isEqualTo(expectedPadding)
+        assertThat(chipView.getAppIconView().paddingTop).isEqualTo(expectedPadding)
+        assertThat(chipView.getAppIconView().paddingBottom).isEqualTo(expectedPadding)
     }
 
     @Test
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 ff0faf9..3a8a51d 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
@@ -17,6 +17,7 @@
 package com.android.systemui.media.taptotransfer.sender
 
 import android.app.StatusBarManager
+import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
 import android.graphics.drawable.Drawable
@@ -35,18 +36,24 @@
 import com.android.internal.statusbar.IUndoMediaTransferCallback
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.media.taptotransfer.common.MediaTttLogger
+import com.android.systemui.media.taptotransfer.receiver.MediaTttReceiverLogger
+import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.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
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
@@ -57,7 +64,7 @@
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
 class MediaTttChipControllerSenderTest : SysuiTestCase() {
-    private lateinit var controllerSender: MediaTttChipControllerSender
+    private lateinit var controllerSender: TestMediaTttChipControllerSender
 
     @Mock
     private lateinit var packageManager: PackageManager
@@ -75,6 +82,12 @@
     private lateinit var windowManager: WindowManager
     @Mock
     private lateinit var commandQueue: CommandQueue
+    @Mock
+    private lateinit var falsingManager: FalsingManager
+    @Mock
+    private lateinit var falsingCollector: FalsingCollector
+    @Mock
+    private lateinit var viewUtil: ViewUtil
     private lateinit var commandQueueCallback: CommandQueue.Callbacks
     private lateinit var fakeAppIconDrawable: Drawable
     private lateinit var fakeClock: FakeSystemClock
@@ -102,7 +115,7 @@
 
         whenever(accessibilityManager.getRecommendedTimeoutMillis(any(), any())).thenReturn(TIMEOUT)
 
-        controllerSender = MediaTttChipControllerSender(
+        controllerSender = TestMediaTttChipControllerSender(
             commandQueue,
             context,
             logger,
@@ -111,8 +124,12 @@
             accessibilityManager,
             configurationController,
             powerManager,
-            senderUiEventLogger
+            senderUiEventLogger,
+            falsingManager,
+            falsingCollector,
+            viewUtil,
         )
+        controllerSender.start()
 
         val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
         verify(commandQueue).addCallback(callbackCaptor.capture())
@@ -417,6 +434,38 @@
     }
 
     @Test
+    fun transferToReceiverSucceeded_withUndoRunnable_falseTap_callbackNotRun() {
+        whenever(falsingManager.isFalseTap(anyInt())).thenReturn(true)
+        var undoCallbackCalled = false
+        val undoCallback = object : IUndoMediaTransferCallback.Stub() {
+            override fun onUndoTriggered() {
+                undoCallbackCalled = true
+            }
+        }
+
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
+        getChipView().getUndoButton().performClick()
+
+        assertThat(undoCallbackCalled).isFalse()
+    }
+
+    @Test
+    fun transferToReceiverSucceeded_withUndoRunnable_realTap_callbackRun() {
+        whenever(falsingManager.isFalseTap(anyInt())).thenReturn(false)
+        var undoCallbackCalled = false
+        val undoCallback = object : IUndoMediaTransferCallback.Stub() {
+            override fun onUndoTriggered() {
+                undoCallbackCalled = true
+            }
+        }
+
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
+        getChipView().getUndoButton().performClick()
+
+        assertThat(undoCallbackCalled).isTrue()
+    }
+
+    @Test
     fun transferToReceiverSucceeded_undoButtonClick_switchesToTransferToThisDeviceTriggered() {
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
@@ -773,6 +822,39 @@
     /** Helper method providing default parameters to not clutter up the tests. */
     private fun transferToThisDeviceFailed() =
         ChipSenderInfo(ChipStateSender.TRANSFER_TO_RECEIVER_FAILED, routeInfo)
+
+    private class TestMediaTttChipControllerSender(
+        commandQueue: CommandQueue,
+        context: Context,
+        @MediaTttReceiverLogger logger: MediaTttLogger,
+        windowManager: WindowManager,
+        mainExecutor: DelayableExecutor,
+        accessibilityManager: AccessibilityManager,
+        configurationController: ConfigurationController,
+        powerManager: PowerManager,
+        uiEventLogger: MediaTttSenderUiEventLogger,
+        falsingManager: FalsingManager,
+        falsingCollector: FalsingCollector,
+        viewUtil: ViewUtil,
+    ) : MediaTttChipControllerSender(
+        commandQueue,
+        context,
+        logger,
+        windowManager,
+        mainExecutor,
+        accessibilityManager,
+        configurationController,
+        powerManager,
+        uiEventLogger,
+        falsingManager,
+        falsingCollector,
+        viewUtil,
+    ) {
+        override fun animateViewOut(view: ViewGroup, onAnimationEnd: Runnable) {
+            // Just bypass the animation in tests
+            onAnimationEnd.run()
+        }
+    }
 }
 
 private const val APP_NAME = "Fake app name"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
index 37b7f47..19d2d33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/MediaProjectionAppSelectorControllerTest.kt
@@ -25,6 +25,7 @@
 
     private val controller = MediaProjectionAppSelectorController(
         taskListProvider,
+        view,
         scope,
         appSelectorComponentName
     )
@@ -33,7 +34,7 @@
     fun initNoRecentTasks_bindsEmptyList() {
         taskListProvider.tasks = emptyList()
 
-        controller.init(view)
+        controller.init()
 
         verify(view).bind(emptyList())
     }
@@ -44,7 +45,7 @@
             createRecentTask(taskId = 1)
         )
 
-        controller.init(view)
+        controller.init()
 
         verify(view).bind(
             listOf(
@@ -54,7 +55,7 @@
     }
 
     @Test
-    fun initMultipleRecentTasksWithoutAppSelectorTask_bindsListInReverse() {
+    fun initMultipleRecentTasksWithoutAppSelectorTask_bindsListInTheSameOrder() {
         val tasks = listOf(
             createRecentTask(taskId = 1),
             createRecentTask(taskId = 2),
@@ -62,19 +63,19 @@
         )
         taskListProvider.tasks = tasks
 
-        controller.init(view)
+        controller.init()
 
         verify(view).bind(
             listOf(
-                createRecentTask(taskId = 3),
-                createRecentTask(taskId = 2),
                 createRecentTask(taskId = 1),
+                createRecentTask(taskId = 2),
+                createRecentTask(taskId = 3),
             )
         )
     }
 
     @Test
-    fun initRecentTasksWithAppSelectorTasks_bindsListInReverseAndAppSelectorTasksAtTheEnd() {
+    fun initRecentTasksWithAppSelectorTasks_bindsAppSelectorTasksAtTheEnd() {
         val tasks = listOf(
             createRecentTask(taskId = 1),
             createRecentTask(taskId = 2, topActivityComponent = appSelectorComponentName),
@@ -84,15 +85,15 @@
         )
         taskListProvider.tasks = tasks
 
-        controller.init(view)
+        controller.init()
 
         verify(view).bind(
             listOf(
-                createRecentTask(taskId = 5),
-                createRecentTask(taskId = 3),
                 createRecentTask(taskId = 1),
-                createRecentTask(taskId = 4, topActivityComponent = appSelectorComponentName),
+                createRecentTask(taskId = 3),
+                createRecentTask(taskId = 5),
                 createRecentTask(taskId = 2, topActivityComponent = appSelectorComponentName),
+                createRecentTask(taskId = 4, topActivityComponent = appSelectorComponentName),
             )
         )
     }
@@ -105,7 +106,8 @@
             taskId = taskId,
             topActivityComponent = topActivityComponent,
             baseIntentComponent = ComponentName("com", "Test"),
-            userId = 0
+            userId = 0,
+            colorBackground = 0
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
new file mode 100644
index 0000000..939af16
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/data/ShellRecentTaskListProviderTest.kt
@@ -0,0 +1,112 @@
+package com.android.systemui.mediaprojection.appselector.data
+
+import android.app.ActivityManager.RecentTaskInfo
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.wm.shell.recents.RecentTasks
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import com.google.common.truth.Truth.assertThat
+import java.util.*
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.function.Consumer
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ShellRecentTaskListProviderTest : SysuiTestCase() {
+
+    private val dispatcher = Dispatchers.Unconfined
+    private val recentTasks: RecentTasks = mock()
+    private val recentTaskListProvider =
+        ShellRecentTaskListProvider(dispatcher, Runnable::run, Optional.of(recentTasks))
+
+    @Test
+    fun loadRecentTasks_oneTask_returnsTheSameTask() {
+        givenRecentTasks(createSingleTask(taskId = 1))
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result).containsExactly(createRecentTask(taskId = 1))
+    }
+
+    @Test
+    fun loadRecentTasks_multipleTasks_returnsTheSameTasks() {
+        givenRecentTasks(
+            createSingleTask(taskId = 1),
+            createSingleTask(taskId = 2),
+            createSingleTask(taskId = 3),
+        )
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result)
+            .containsExactly(
+                createRecentTask(taskId = 1),
+                createRecentTask(taskId = 2),
+                createRecentTask(taskId = 3),
+            )
+    }
+
+    @Test
+    fun loadRecentTasks_groupedTask_returnsUngroupedTasks() {
+        givenRecentTasks(createTaskPair(taskId1 = 1, taskId2 = 2))
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result)
+            .containsExactly(createRecentTask(taskId = 1), createRecentTask(taskId = 2))
+    }
+
+    @Test
+    fun loadRecentTasks_mixedSingleAndGroupedTask_returnsUngroupedTasks() {
+        givenRecentTasks(
+            createSingleTask(taskId = 1),
+            createTaskPair(taskId1 = 2, taskId2 = 3),
+            createSingleTask(taskId = 4),
+            createTaskPair(taskId1 = 5, taskId2 = 6),
+        )
+
+        val result = runBlocking { recentTaskListProvider.loadRecentTasks() }
+
+        assertThat(result)
+            .containsExactly(
+                createRecentTask(taskId = 1),
+                createRecentTask(taskId = 2),
+                createRecentTask(taskId = 3),
+                createRecentTask(taskId = 4),
+                createRecentTask(taskId = 5),
+                createRecentTask(taskId = 6),
+            )
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    private fun givenRecentTasks(vararg tasks: GroupedRecentTaskInfo) {
+        whenever(recentTasks.getRecentTasks(any(), any(), any(), any(), any())).thenAnswer {
+            val consumer = it.arguments.last() as Consumer<List<GroupedRecentTaskInfo>>
+            consumer.accept(tasks.toList())
+        }
+    }
+
+    private fun createRecentTask(taskId: Int): RecentTask =
+        RecentTask(
+            taskId = taskId,
+            userId = 0,
+            topActivityComponent = null,
+            baseIntentComponent = null,
+            colorBackground = null
+        )
+
+    private fun createSingleTask(taskId: Int): GroupedRecentTaskInfo =
+        GroupedRecentTaskInfo.forSingleTask(createTaskInfo(taskId))
+
+    private fun createTaskPair(taskId1: Int, taskId2: Int): GroupedRecentTaskInfo =
+        GroupedRecentTaskInfo.forSplitTasks(createTaskInfo(taskId1), createTaskInfo(taskId2), null)
+
+    private fun createTaskInfo(taskId: Int) = RecentTaskInfo().apply { this.taskId = taskId }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
new file mode 100644
index 0000000..464acb6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/appselector/view/TaskPreviewSizeProviderTest.kt
@@ -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.systemui.mediaprojection.appselector.view
+
+import android.content.Context
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.graphics.Rect
+import android.util.DisplayMetrics.DENSITY_DEFAULT
+import android.view.WindowManager
+import android.view.WindowMetrics
+import androidx.test.filters.SmallTest
+import com.android.internal.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.mediaprojection.appselector.view.TaskPreviewSizeProvider.TaskPreviewSizeListener
+import com.android.systemui.statusbar.policy.FakeConfigurationController
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.min
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class TaskPreviewSizeProviderTest : SysuiTestCase() {
+
+    private val mockContext: Context = mock()
+    private val resources: Resources = mock()
+    private val windowManager: WindowManager = mock()
+    private val sizeUpdates = arrayListOf<Rect>()
+    private val testConfigurationController = FakeConfigurationController()
+
+    @Before
+    fun setup() {
+        whenever(mockContext.getSystemService(eq(WindowManager::class.java)))
+            .thenReturn(windowManager)
+        whenever(mockContext.resources).thenReturn(resources)
+    }
+
+    @Test
+    fun size_phoneDisplay_thumbnailSizeIsSmallerAndProportionalToTheScreenSize() {
+        givenDisplay(width = 400, height = 600, isTablet = false)
+
+        val size = createSizeProvider().size
+
+        assertThat(size).isEqualTo(Rect(0, 0, 100, 150))
+    }
+
+    @Test
+    fun size_tabletDisplay_thumbnailSizeProportionalToTheScreenSizeExcludingTaskbar() {
+        givenDisplay(width = 400, height = 600, isTablet = true)
+        givenTaskbarSize(20)
+
+        val size = createSizeProvider().size
+
+        assertThat(size).isEqualTo(Rect(0, 0, 97, 140))
+    }
+
+    @Test
+    fun size_phoneDisplayAndRotate_emitsSizeUpdate() {
+        givenDisplay(width = 400, height = 600, isTablet = false)
+        createSizeProvider()
+
+        givenDisplay(width = 600, height = 400, isTablet = false)
+        testConfigurationController.onConfigurationChanged(Configuration())
+
+        assertThat(sizeUpdates).containsExactly(Rect(0, 0, 150, 100))
+    }
+
+    @Test
+    fun size_phoneDisplayAndRotateConfigurationChange_returnsUpdatedSize() {
+        givenDisplay(width = 400, height = 600, isTablet = false)
+        val sizeProvider = createSizeProvider()
+
+        givenDisplay(width = 600, height = 400, isTablet = false)
+        testConfigurationController.onConfigurationChanged(Configuration())
+
+        assertThat(sizeProvider.size).isEqualTo(Rect(0, 0, 150, 100))
+    }
+
+    private fun givenTaskbarSize(size: Int) {
+        whenever(resources.getDimensionPixelSize(eq(R.dimen.taskbar_frame_height))).thenReturn(size)
+    }
+
+    private fun givenDisplay(width: Int, height: Int, isTablet: Boolean = false) {
+        val bounds = Rect(0, 0, width, height)
+        val windowMetrics = WindowMetrics(bounds, null)
+        whenever(windowManager.maximumWindowMetrics).thenReturn(windowMetrics)
+        whenever(windowManager.currentWindowMetrics).thenReturn(windowMetrics)
+
+        val minDimension = min(width, height)
+
+        // Calculate DPI so the smallest width is either considered as tablet or as phone
+        val targetSmallestWidthDpi =
+            if (isTablet) SMALLEST_WIDTH_DPI_TABLET else SMALLEST_WIDTH_DPI_PHONE
+        val densityDpi = minDimension * DENSITY_DEFAULT / targetSmallestWidthDpi
+
+        val configuration = Configuration(context.resources.configuration)
+        configuration.densityDpi = densityDpi
+        whenever(resources.configuration).thenReturn(configuration)
+    }
+
+    private fun createSizeProvider(): TaskPreviewSizeProvider {
+        val listener =
+            object : TaskPreviewSizeListener {
+                override fun onTaskSizeChanged(size: Rect) {
+                    sizeUpdates.add(size)
+                }
+            }
+
+        return TaskPreviewSizeProvider(mockContext, windowManager, testConfigurationController)
+            .also { it.addCallback(listener) }
+    }
+
+    private companion object {
+        private const val SMALLEST_WIDTH_DPI_TABLET = 800
+        private const val SMALLEST_WIDTH_DPI_PHONE = 400
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
index b0cf061..9bf27a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarControllerTest.java
@@ -19,6 +19,8 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -30,20 +32,25 @@
 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.content.res.Configuration;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.util.SparseArray;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoHideController;
 import com.android.systemui.statusbar.phone.LightBarController;
@@ -72,11 +79,14 @@
     private NavigationBarController mNavigationBarController;
     private NavigationBar mDefaultNavBar;
     private NavigationBar mSecondaryNavBar;
+    private StaticMockitoSession mMockitoSession;
 
     @Mock
     private CommandQueue mCommandQueue;
     @Mock
     private NavigationBarComponent.Factory mNavigationBarFactory;
+    @Mock
+    TaskbarDelegate mTaskbarDelegate;
 
     @Before
     public void setUp() {
@@ -90,7 +100,7 @@
                         Dependency.get(Dependency.MAIN_HANDLER),
                         mock(ConfigurationController.class),
                         mock(NavBarHelper.class),
-                        mock(TaskbarDelegate.class),
+                        mTaskbarDelegate,
                         mNavigationBarFactory,
                         mock(StatusBarKeyguardViewManager.class),
                         mock(DumpManager.class),
@@ -100,6 +110,7 @@
                         Optional.of(mock(BackAnimation.class)),
                         mock(FeatureFlags.class)));
         initializeNavigationBars();
+        mMockitoSession = mockitoSession().mockStatic(Utilities.class).startMocking();
     }
 
     private void initializeNavigationBars() {
@@ -120,6 +131,7 @@
         mNavigationBarController = null;
         mDefaultNavBar = null;
         mSecondaryNavBar = null;
+        mMockitoSession.finishMocking();
     }
 
     @Test
@@ -268,4 +280,22 @@
     public void test3ButtonTaskbarFlagDisabledNoRegister() {
         verify(mCommandQueue, never()).addCallback(any(TaskbarDelegate.class));
     }
+
+
+    @Test
+    public void testConfigurationChange_taskbarNotInitialized() {
+        Configuration configuration = mContext.getResources().getConfiguration();
+        when(Utilities.isTablet(any())).thenReturn(true);
+        mNavigationBarController.onConfigChanged(configuration);
+        verify(mTaskbarDelegate, never()).onConfigurationChanged(configuration);
+    }
+
+    @Test
+    public void testConfigurationChange_taskbarInitialized() {
+        Configuration configuration = mContext.getResources().getConfiguration();
+        when(Utilities.isTablet(any())).thenReturn(true);
+        when(mTaskbarDelegate.isInitialized()).thenReturn(true);
+        mNavigationBarController.onConfigChanged(configuration);
+        verify(mTaskbarDelegate, times(1)).onConfigurationChanged(configuration);
+    }
 }
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 5d5918d..d2c2d58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -14,6 +14,9 @@
 
 package com.android.systemui.qs;
 
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertTrue;
@@ -49,13 +52,13 @@
 import com.android.systemui.flags.Flags;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.customize.QSCustomizerController;
 import com.android.systemui.qs.dagger.QSFragmentComponent;
 import com.android.systemui.qs.external.TileServiceRequestController;
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
@@ -93,7 +96,7 @@
     @Mock private QSPanel.QSTileLayout mQsTileLayout;
     @Mock private QSPanel.QSTileLayout mQQsTileLayout;
     @Mock private QSAnimator mQSAnimator;
-    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private SysuiStatusBarStateController mStatusBarStateController;
     @Mock private QSSquishinessController mSquishinessController;
     private View mQsFragmentView;
 
@@ -158,7 +161,7 @@
     public void
             transitionToFullShade_onKeyguard_noBouncer_setsAlphaUsingLinearInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        setStatusBarState(StatusBarState.KEYGUARD);
+        setStatusBarState(KEYGUARD);
         when(mQSPanelController.isBouncerInTransit()).thenReturn(false);
         boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
@@ -174,7 +177,7 @@
     public void
             transitionToFullShade_onKeyguard_bouncerActive_setsAlphaUsingBouncerInterpolator() {
         QSFragment fragment = resumeAndGetFragment();
-        setStatusBarState(StatusBarState.KEYGUARD);
+        setStatusBarState(KEYGUARD);
         when(mQSPanelController.isBouncerInTransit()).thenReturn(true);
         boolean isTransitioningToFullShade = true;
         float transitionProgress = 0.5f;
@@ -262,6 +265,27 @@
     }
 
     @Test
+    public void setQsExpansion_inSplitShade_whenTransitioningToKeyguard_setsAlphaBasedOnShadeTransitionProgress() {
+        QSFragment fragment = resumeAndGetFragment();
+        enableSplitShade();
+        when(mStatusBarStateController.getState()).thenReturn(SHADE);
+        when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
+        boolean isTransitioningToFullShade = false;
+        float transitionProgress = 0;
+        float squishinessFraction = 0f;
+
+        fragment.setTransitionToFullShadeProgress(isTransitioningToFullShade, transitionProgress,
+                squishinessFraction);
+
+        // trigger alpha refresh with non-zero expansion and fraction values
+        fragment.setQsExpansion(/* expansion= */ 1, /* panelExpansionFraction= */1,
+                /* proposedTranslation= */ 0, /* squishinessFraction= */ 1);
+
+        // alpha should follow lockscreen to shade progress, not panel expansion fraction
+        assertThat(mQsFragmentView.getAlpha()).isEqualTo(transitionProgress);
+    }
+
+    @Test
     public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() {
         QSFragment fragment = resumeAndGetFragment();
         disableSplitShade();
@@ -402,6 +426,19 @@
         verify(mQSPanelController).setListening(eq(true), anyBoolean());
     }
 
+    @Test
+    public void passCorrectExpansionState_inSplitShade() {
+        QSFragment fragment = resumeAndGetFragment();
+        enableSplitShade();
+        clearInvocations(mQSPanelController);
+
+        fragment.setExpanded(true);
+        verify(mQSPanelController).setExpanded(true);
+
+        fragment.setExpanded(false);
+        verify(mQSPanelController).setExpanded(false);
+    }
+
     @Override
     protected Fragment instantiate(Context context, String className, Bundle arguments) {
         MockitoAnnotations.initMocks(this);
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 cbe1186..b847ad0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -44,7 +44,6 @@
 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;
@@ -87,7 +86,6 @@
     @Mock
     private QSLogger mQSLogger;
     private DumpManager mDumpManager = new DumpManager();
-    private MediaCarouselController mMediaCarouselController;
     @Mock
     QSTileImpl mQSTile;
     @Mock
@@ -110,9 +108,9 @@
         protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
                 QSCustomizerController qsCustomizerController, MediaHost mediaHost,
                 MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-                DumpManager dumpManager, MediaCarouselController mediaCarouselController) {
+                DumpManager dumpManager) {
             super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,
-                    qsLogger, dumpManager, mediaCarouselController);
+                    qsLogger, dumpManager);
         }
 
         @Override
@@ -146,7 +144,7 @@
 
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
 
         mController.init();
         reset(mQSTileRevealController);
@@ -158,7 +156,7 @@
 
         QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
                 mQSTileHost, mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController) {
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager) {
             @Override
             protected QSTileRevealController createTileRevealController() {
                 return mQSTileRevealController;
@@ -253,7 +251,7 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
         mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isTrue();
@@ -262,7 +260,7 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
         mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isFalse();
@@ -279,7 +277,7 @@
 
         // Then the layout changes
         assertThat(mController.shouldUseHorizontalLayout()).isTrue();
-        verify(mHorizontalLayoutListener).run(); // not invoked
+        verify(mHorizontalLayoutListener).run();
 
         // When it is rotated back to portrait
         mConfiguration.orientation = Configuration.ORIENTATION_PORTRAIT;
@@ -302,4 +300,24 @@
         verify(mQSTile).refreshState();
         verify(mOtherTile, never()).refreshState();
     }
+
+    @Test
+    public void configurationChange_onlySplitShadeConfigChanges_horizontalLayoutStatusUpdated() {
+        // Preconditions for horizontal layout
+        when(mMediaHost.getVisible()).thenReturn(true);
+        when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(false);
+        mConfiguration.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mController.setUsingHorizontalLayoutChangeListener(mHorizontalLayoutListener);
+        mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
+        assertThat(mController.shouldUseHorizontalLayout()).isTrue();
+        reset(mHorizontalLayoutListener);
+
+        // Only split shade status changes
+        when(mResources.getBoolean(R.bool.config_use_split_notification_shade)).thenReturn(true);
+        mController.mOnConfigurationChangedListener.onConfigurationChange(mConfiguration);
+
+        // Horizontal layout is updated accordingly.
+        assertThat(mController.shouldUseHorizontalLayout()).isFalse();
+        verify(mHorizontalLayoutListener).run();
+    }
 }
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 98d499a..e539705 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -6,7 +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.flags.FeatureFlags
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.FalsingManager
@@ -41,7 +41,6 @@
     @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
@@ -54,6 +53,7 @@
     @Mock private lateinit var tile: QSTile
     @Mock private lateinit var otherTile: QSTile
     @Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
+    @Mock private lateinit var featureFlags: FeatureFlags
 
     private lateinit var controller: QSPanelController
 
@@ -78,14 +78,14 @@
             mediaHost,
             qsTileRevealControllerFactory,
             dumpManager,
-            mediaCarouselController,
             metricsLogger,
             uiEventLogger,
             qsLogger,
             brightnessControllerFactory,
             brightnessSliderFactory,
             falsingManager,
-            statusBarKeyguardViewManager
+            statusBarKeyguardViewManager,
+            featureFlags
         )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 2db58be..7c930b1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -159,6 +159,32 @@
     }
 
     @Test
+    fun testTopPadding_notCombinedHeaders() {
+        qsPanel.setUsingCombinedHeaders(false)
+        val padding = 10
+        val paddingCombined = 100
+        context.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, padding)
+        context.orCreateTestableResources.addOverride(
+                R.dimen.qs_panel_padding_top_combined_headers, paddingCombined)
+
+        qsPanel.updatePadding()
+        assertThat(qsPanel.paddingTop).isEqualTo(padding)
+    }
+
+    @Test
+    fun testTopPadding_combinedHeaders() {
+        qsPanel.setUsingCombinedHeaders(true)
+        val padding = 10
+        val paddingCombined = 100
+        context.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, padding)
+        context.orCreateTestableResources.addOverride(
+                R.dimen.qs_panel_padding_top_combined_headers, paddingCombined)
+
+        qsPanel.updatePadding()
+        assertThat(qsPanel.paddingTop).isEqualTo(paddingCombined)
+    }
+
+    @Test
     fun testSetSquishinessFraction_noCrash() {
         qsPanel.addView(qsPanel.mTileLayout as View, 0)
         qsPanel.addView(FrameLayout(context))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 233c267..1c686c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -726,7 +726,7 @@
         when(mSecurityController.isParentalControlsEnabled()).thenReturn(true);
         when(mSecurityController.getLabel(any())).thenReturn(PARENTAL_CONTROLS_LABEL);
 
-        View view = mFooterUtils.createDialogView();
+        View view = mFooterUtils.createDialogView(getContext());
         TextView textView = (TextView) view.findViewById(R.id.parental_controls_title);
         assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText());
     }
@@ -749,7 +749,7 @@
         when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
                 .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
 
-        View view = mFooterUtils.createDialogView();
+        View view = mFooterUtils.createDialogView(getContext());
 
         TextView managementSubtitle = view.findViewById(R.id.device_management_subtitle);
         assertEquals(View.VISIBLE, managementSubtitle.getVisibility());
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 4af5b90..6af8e49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,7 +23,6 @@
 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
@@ -60,7 +59,6 @@
     @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()
@@ -90,8 +88,7 @@
                 metricsLogger,
                 uiEventLogger,
                 qsLogger,
-                dumpManager,
-                mediaCarouselController)
+                dumpManager)
 
         controller.init()
     }
@@ -158,8 +155,7 @@
         metricsLogger: MetricsLogger,
         uiEventLogger: UiEventLoggerFake,
         qsLogger: QSLogger,
-        dumpManager: DumpManager,
-        mediaCarouselController: MediaCarouselController
+        dumpManager: DumpManager
     ) :
         QuickQSPanelController(
             view,
@@ -171,8 +167,7 @@
             metricsLogger,
             uiEventLogger,
             qsLogger,
-            dumpManager,
-            mediaCarouselController) {
+            dumpManager) {
 
         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 eb907bd..39d89bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -110,7 +110,7 @@
         `when`(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController)
         `when`(variableDateViewControllerFactory.create(any()))
                 .thenReturn(variableDateViewController)
-        `when`(iconManagerFactory.create(any())).thenReturn(iconManager)
+        `when`(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
         `when`(view.resources).thenReturn(mContext.resources)
         `when`(view.isAttachedToWindow).thenReturn(true)
         `when`(view.context).thenReturn(context)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
index 7d56339..4c44dac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ImageExporterTest.java
@@ -33,6 +33,7 @@
 import android.graphics.Paint;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.provider.MediaStore;
 import android.testing.AndroidTestingRunner;
 
@@ -97,7 +98,8 @@
         Bitmap original = createCheckerBitmap(10, 10, 10);
 
         ListenableFuture<ImageExporter.Result> direct =
-                exporter.export(DIRECT_EXECUTOR, requestId, original, CAPTURE_TIME);
+                exporter.export(DIRECT_EXECUTOR, requestId, original, CAPTURE_TIME,
+                        Process.myUserHandle());
         assertTrue("future should be done", direct.isDone());
         assertFalse("future should not be canceled", direct.isCancelled());
         ImageExporter.Result result = direct.get();
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 073c23c..5cb27a4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/RequestProcessorTest.kt
@@ -28,7 +28,6 @@
 import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
 import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
 import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
 import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
 import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler.bundleToHardwareBitmap
 import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
@@ -140,66 +139,6 @@
     }
 
     @Test
-    fun testSelectedRegionScreenshot_workProfilePolicyDisabled() = runBlocking {
-        flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
-
-        val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
-        val processor = RequestProcessor(imageCapture, policy, flags, scope)
-
-        val processedRequest = processor.process(request)
-
-        // No changes
-        assertThat(processedRequest).isEqualTo(request)
-     }
-
-    @Test
-    fun testSelectedRegionScreenshot() = runBlocking {
-        flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
-        val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
-        val processor = RequestProcessor(imageCapture, policy, flags, scope)
-
-        policy.setManagedProfile(USER_ID, false)
-        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
-            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
-
-        val processedRequest = processor.process(request)
-
-        // Request has topComponent added, but otherwise unchanged.
-        assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_FULLSCREEN)
-        assertThat(processedRequest.topComponent).isEqualTo(component)
-    }
-
-    @Test
-    fun testSelectedRegionScreenshot_managedProfile() = runBlocking {
-        flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, true)
-
-        // Provide a fake task bitmap when asked
-        val bitmap = makeHardwareBitmap(100, 100)
-        imageCapture.image = bitmap
-
-        val request = ScreenshotRequest(TAKE_SCREENSHOT_SELECTED_REGION, SCREENSHOT_KEY_CHORD)
-        val processor = RequestProcessor(imageCapture, policy, flags, scope)
-
-        // Indicate that the primary content belongs to a manged profile
-        policy.setManagedProfile(USER_ID, true)
-        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
-            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))
-
-        val processedRequest = processor.process(request)
-
-        // Expect a task snapshot is taken, overriding the selected region mode
-        assertThat(processedRequest.type).isEqualTo(TAKE_SCREENSHOT_PROVIDED_IMAGE)
-        assertThat(bitmap.equalsHardwareBitmapBundle(processedRequest.bitmapBundle)).isTrue()
-        assertThat(processedRequest.boundsInScreen).isEqualTo(bounds)
-        assertThat(processedRequest.insets).isEqualTo(Insets.NONE)
-        assertThat(processedRequest.taskId).isEqualTo(TASK_ID)
-        assertThat(imageCapture.requestedTaskId).isEqualTo(TASK_ID)
-        assertThat(processedRequest.userId).isEqualTo(USER_ID)
-        assertThat(processedRequest.topComponent).isEqualTo(component)
-    }
-
-    @Test
     fun testProvidedImageScreenshot_workProfilePolicyDisabled() = runBlocking {
         flags.set(Flags.SCREENSHOT_WORK_PROFILE_POLICY, false)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
index 69b7b88..8c9404e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
@@ -180,7 +180,7 @@
         data.finisher = null;
         data.mActionsReadyListener = null;
         SaveImageInBackgroundTask task =
-                new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
+                new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data,
                         ActionTransition::new, mSmartActionsProvider);
 
         Notification.Action shareAction = task.createShareAction(mContext, mContext.getResources(),
@@ -208,7 +208,7 @@
         data.finisher = null;
         data.mActionsReadyListener = null;
         SaveImageInBackgroundTask task =
-                new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
+                new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data,
                         ActionTransition::new, mSmartActionsProvider);
 
         Notification.Action editAction = task.createEditAction(mContext, mContext.getResources(),
@@ -236,7 +236,7 @@
         data.finisher = null;
         data.mActionsReadyListener = null;
         SaveImageInBackgroundTask task =
-                new SaveImageInBackgroundTask(mContext, null, mScreenshotSmartActions, data,
+                new SaveImageInBackgroundTask(mContext, null, null, mScreenshotSmartActions, data,
                         ActionTransition::new, mSmartActionsProvider);
 
         Notification.Action deleteAction = task.createDeleteAction(mContext,
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 002ef29..3a4da86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/TakeScreenshotServiceTest.kt
@@ -33,7 +33,6 @@
 import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW
 import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
 import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
-import android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.internal.util.ScreenshotHelper
@@ -175,28 +174,6 @@
     }
 
     @Test
-    fun takeScreenshotPartial() {
-        val request = ScreenshotRequest(
-            TAKE_SCREENSHOT_SELECTED_REGION,
-            SCREENSHOT_KEY_CHORD,
-            /* topComponent = */ null)
-
-        service.handleRequest(request, { /* onSaved */ }, callback)
-
-        verify(controller, times(1)).takeScreenshotPartial(
-            /* topComponent = */ isNull(),
-            /* 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 empty package name in UiEvent", "", eventLogger.get(0).packageName)
-    }
-
-    @Test
     fun takeScreenshotProvidedImage() {
         val bounds = Rect(50, 50, 150, 150)
         val bitmap = makeHardwareBitmap(100, 100)
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 c448538..c76d9e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -176,7 +176,7 @@
         }
         whenever(view.visibility).thenAnswer { _ -> viewVisibility }
 
-        whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
+        whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
 
         whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(true)
         whenever(featureFlags.isEnabled(Flags.NEW_HEADER)).thenReturn(true)
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 5ecfc8eb..90ae693 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -97,7 +97,7 @@
         whenever(view.visibility).thenAnswer { _ -> viewVisibility }
         whenever(variableDateViewControllerFactory.create(any()))
             .thenReturn(variableDateViewController)
-        whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
+        whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
         whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(false)
         mLargeScreenShadeHeaderController = LargeScreenShadeHeaderController(
                 view,
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 b40d5ac..0c60d3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -23,6 +23,9 @@
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
+import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_CLOSED;
+import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPEN;
+import static com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManagerKt.STATE_OPENING;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -1249,14 +1252,10 @@
     @Test
     public void testQsToBeImmediatelyExpandedWhenOpeningPanelInSplitShade() {
         enableSplitShade(/* enabled= */ true);
-        // set panel state to CLOSED
-        mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 0,
-                /* expanded= */ false, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+        mPanelExpansionStateManager.updateState(STATE_CLOSED);
         assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
 
-        // change panel state to OPENING
-        mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 0.5f,
-                /* expanded= */ true, /* tracking= */ true, /* dragDownPxAmount= */ 100);
+        mPanelExpansionStateManager.updateState(STATE_OPENING);
 
         assertThat(mNotificationPanelViewController.mQsExpandImmediate).isTrue();
     }
@@ -1264,19 +1263,27 @@
     @Test
     public void testQsNotToBeImmediatelyExpandedWhenGoingFromUnlockedToLocked() {
         enableSplitShade(/* enabled= */ true);
-        // set panel state to CLOSED
-        mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 0,
-                /* expanded= */ false, /* tracking= */ false, /* dragDownPxAmount= */ 0);
+        mPanelExpansionStateManager.updateState(STATE_CLOSED);
 
-        // go to lockscreen, which also sets fraction to 1.0f and makes shade "expanded"
         mStatusBarStateController.setState(KEYGUARD);
-        mPanelExpansionStateManager.onPanelExpansionChanged(/* fraction= */ 1,
-                /* expanded= */ true, /* tracking= */ true, /* dragDownPxAmount= */ 0);
+        // going to lockscreen would trigger STATE_OPENING
+        mPanelExpansionStateManager.updateState(STATE_OPENING);
 
         assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
     }
 
     @Test
+    public void testQsImmediateResetsWhenPanelOpensOrCloses() {
+        mNotificationPanelViewController.mQsExpandImmediate = true;
+        mPanelExpansionStateManager.updateState(STATE_OPEN);
+        assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+
+        mNotificationPanelViewController.mQsExpandImmediate = true;
+        mPanelExpansionStateManager.updateState(STATE_CLOSED);
+        assertThat(mNotificationPanelViewController.mQsExpandImmediate).isFalse();
+    }
+
+    @Test
     public void testQsExpansionChangedToDefaultWhenRotatingFromOrToSplitShade() {
         // to make sure shade is in expanded state
         mNotificationPanelViewController.startWaitingForOpenPanelGesture();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
index a4a89a4..7a74b12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/animation/UnfoldConstantTranslateAnimatorTest.kt
@@ -27,8 +27,8 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -42,8 +42,8 @@
 
     private val viewsIdToRegister =
         setOf(
-            ViewIdToTranslate(LEFT_VIEW_ID, Direction.LEFT),
-            ViewIdToTranslate(RIGHT_VIEW_ID, Direction.RIGHT))
+            ViewIdToTranslate(START_VIEW_ID, Direction.START),
+            ViewIdToTranslate(END_VIEW_ID, Direction.END))
 
     @Before
     fun setup() {
@@ -66,41 +66,62 @@
     }
 
     @Test
-    fun onTransition_oneMovesLeft() {
+    fun onTransition_oneMovesStartWithLTR() {
         // GIVEN one view with a matching id
         val view = View(context)
-        whenever(parent.findViewById<View>(LEFT_VIEW_ID)).thenReturn(view)
+        whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(view)
 
-        moveAndValidate(listOf(view to LEFT))
+        moveAndValidate(listOf(view to START), View.LAYOUT_DIRECTION_LTR)
     }
 
     @Test
-    fun onTransition_oneMovesLeftAndOneMovesRightMultipleTimes() {
+    fun onTransition_oneMovesStartWithRTL() {
+        // GIVEN one view with a matching id
+        val view = View(context)
+        whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(view)
+
+        whenever(parent.getLayoutDirection()).thenReturn(View.LAYOUT_DIRECTION_RTL)
+        moveAndValidate(listOf(view to START), View.LAYOUT_DIRECTION_RTL)
+    }
+
+    @Test
+    fun onTransition_oneMovesStartAndOneMovesEndMultipleTimes() {
         // GIVEN two views with a matching id
         val leftView = View(context)
         val rightView = View(context)
-        whenever(parent.findViewById<View>(LEFT_VIEW_ID)).thenReturn(leftView)
-        whenever(parent.findViewById<View>(RIGHT_VIEW_ID)).thenReturn(rightView)
+        whenever(parent.findViewById<View>(START_VIEW_ID)).thenReturn(leftView)
+        whenever(parent.findViewById<View>(END_VIEW_ID)).thenReturn(rightView)
 
-        moveAndValidate(listOf(leftView to LEFT, rightView to RIGHT))
-        moveAndValidate(listOf(leftView to LEFT, rightView to RIGHT))
+        moveAndValidate(listOf(leftView to START, rightView to END), View.LAYOUT_DIRECTION_LTR)
+        moveAndValidate(listOf(leftView to START, rightView to END), View.LAYOUT_DIRECTION_LTR)
     }
 
-    private fun moveAndValidate(list: List<Pair<View, Int>>) {
+    private fun moveAndValidate(list: List<Pair<View, Int>>, layoutDirection: Int) {
         // Compare values as ints because -0f != 0f
 
         // WHEN the transition starts
         progressProvider.onTransitionStarted()
         progressProvider.onTransitionProgress(0f)
 
+        val rtlMultiplier = if (layoutDirection == View.LAYOUT_DIRECTION_LTR) {
+            1
+        } else {
+            -1
+        }
         list.forEach { (view, direction) ->
-            assertEquals((-MAX_TRANSLATION * direction).toInt(), view.translationX.toInt())
+            assertEquals(
+                (-MAX_TRANSLATION * direction * rtlMultiplier).toInt(),
+                view.translationX.toInt()
+            )
         }
 
         // WHEN the transition progresses, translation is updated
         progressProvider.onTransitionProgress(.5f)
         list.forEach { (view, direction) ->
-            assertEquals((-MAX_TRANSLATION / 2f * direction).toInt(), view.translationX.toInt())
+            assertEquals(
+                (-MAX_TRANSLATION / 2f * direction * rtlMultiplier).toInt(),
+                view.translationX.toInt()
+            )
         }
 
         // WHEN the transition ends, translation is completed
@@ -110,12 +131,12 @@
     }
 
     companion object {
-        private val LEFT = Direction.LEFT.multiplier.toInt()
-        private val RIGHT = Direction.RIGHT.multiplier.toInt()
+        private val START = Direction.START.multiplier.toInt()
+        private val END = Direction.END.multiplier.toInt()
 
         private const val MAX_TRANSLATION = 42f
 
-        private const val LEFT_VIEW_ID = 1
-        private const val RIGHT_VIEW_ID = 2
+        private const val START_VIEW_ID = 1
+        private const val END_VIEW_ID = 2
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
index 131eac6..ffb41e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/ClockRegistryTest.kt
@@ -22,7 +22,7 @@
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.Clock
+import com.android.systemui.plugins.ClockController
 import com.android.systemui.plugins.ClockId
 import com.android.systemui.plugins.ClockMetadata
 import com.android.systemui.plugins.ClockProviderPlugin
@@ -48,8 +48,8 @@
     @JvmField @Rule val mockito = MockitoJUnit.rule()
     @Mock private lateinit var mockContext: Context
     @Mock private lateinit var mockPluginManager: PluginManager
-    @Mock private lateinit var mockClock: Clock
-    @Mock private lateinit var mockDefaultClock: Clock
+    @Mock private lateinit var mockClock: ClockController
+    @Mock private lateinit var mockDefaultClock: ClockController
     @Mock private lateinit var mockThumbnail: Drawable
     @Mock private lateinit var mockHandler: Handler
     @Mock private lateinit var mockContentResolver: ContentResolver
@@ -60,7 +60,7 @@
     private var settingValue: String = ""
 
     companion object {
-        private fun failFactory(): Clock {
+        private fun failFactory(): ClockController {
             fail("Unexpected call to createClock")
             return null!!
         }
@@ -73,17 +73,17 @@
 
     private class FakeClockPlugin : ClockProviderPlugin {
         private val metadata = mutableListOf<ClockMetadata>()
-        private val createCallbacks = mutableMapOf<ClockId, () -> Clock>()
+        private val createCallbacks = mutableMapOf<ClockId, () -> ClockController>()
         private val thumbnailCallbacks = mutableMapOf<ClockId, () -> Drawable?>()
 
         override fun getClocks() = metadata
-        override fun createClock(id: ClockId): Clock = createCallbacks[id]!!()
+        override fun createClock(id: ClockId): ClockController = createCallbacks[id]!!()
         override fun getClockThumbnail(id: ClockId): Drawable? = thumbnailCallbacks[id]!!()
 
         fun addClock(
             id: ClockId,
             name: String,
-            create: () -> Clock = ::failFactory,
+            create: () -> ClockController = ::failFactory,
             getThumbnail: () -> Drawable? = ::failThumbnail
         ): FakeClockPlugin {
             metadata.add(ClockMetadata(id, name))
@@ -113,7 +113,7 @@
         registry.isEnabled = true
 
         verify(mockPluginManager)
-            .addPluginListener(captor.capture(), eq(ClockProviderPlugin::class.java))
+            .addPluginListener(captor.capture(), eq(ClockProviderPlugin::class.java), eq(true))
         pluginListener = captor.value
     }
 
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 2b4a109..539a54b 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
@@ -17,6 +17,7 @@
 package com.android.systemui.shared.clocks
 
 import android.content.res.Resources
+import android.graphics.Color
 import android.graphics.drawable.Drawable
 import android.testing.AndroidTestingRunner
 import android.util.TypedValue
@@ -25,7 +26,7 @@
 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.shared.clocks.DefaultClockController.Companion.DOZE_COLOR
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
@@ -88,17 +89,20 @@
         // Default clock provider must always provide the default clock
         val clock = provider.createClock(DEFAULT_CLOCK_ID)
         assertNotNull(clock)
-        assertEquals(clock.smallClock, mockSmallClockView)
-        assertEquals(clock.largeClock, mockLargeClockView)
+        assertEquals(mockSmallClockView, clock.smallClock.view)
+        assertEquals(mockLargeClockView, clock.largeClock.view)
     }
 
     @Test
     fun defaultClock_initialize() {
         val clock = provider.createClock(DEFAULT_CLOCK_ID)
+        verify(mockSmallClockView).setColors(Color.MAGENTA, Color.MAGENTA)
+        verify(mockLargeClockView).setColors(Color.MAGENTA, Color.MAGENTA)
+
         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).setColors(eq(DOZE_COLOR), anyInt())
+        verify(mockLargeClockView).setColors(eq(DOZE_COLOR), anyInt())
         verify(mockSmallClockView).onTimeZoneChanged(notNull())
         verify(mockLargeClockView).onTimeZoneChanged(notNull())
         verify(mockSmallClockView).refreshTime()
@@ -147,10 +151,14 @@
     @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())
+        verify(mockSmallClockView).setColors(Color.MAGENTA, Color.MAGENTA)
+        verify(mockLargeClockView).setColors(Color.MAGENTA, Color.MAGENTA)
+
+        clock.events.onColorPaletteChanged(resources)
+
+        verify(mockSmallClockView).setColors(eq(DOZE_COLOR), anyInt())
+        verify(mockLargeClockView).setColors(eq(DOZE_COLOR), anyInt())
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
index 8bc438b..5fc09c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
@@ -15,6 +15,7 @@
  */
 
 package com.android.systemui.shared.navigationbar
+
 import android.graphics.Rect
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -24,15 +25,23 @@
 import androidx.concurrent.futures.DirectExecutor
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+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.time.FakeSystemClock
+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.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
-import org.mockito.Mockito.*
-import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -99,4 +108,39 @@
         regionSamplingHelper.stopAndDestroy()
         verify(compositionListener).unregister(any())
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testCompositionSamplingListener_has_nonEmptyRect() {
+        // simulate race condition
+        val fakeExecutor = FakeExecutor(FakeSystemClock()) // pass in as backgroundExecutor
+        val fakeSamplingCallback = mock(RegionSamplingHelper.SamplingCallback::class.java)
+
+        whenever(fakeSamplingCallback.isSamplingEnabled).thenReturn(true)
+        whenever(wrappedSurfaceControl.isValid).thenReturn(true)
+
+        regionSamplingHelper = object : RegionSamplingHelper(sampledView, fakeSamplingCallback,
+                DirectExecutor.INSTANCE, fakeExecutor, compositionListener) {
+            override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
+                return wrappedSurfaceControl
+            }
+        }
+        regionSamplingHelper.setWindowVisible(true)
+        regionSamplingHelper.start(Rect(0, 0, 100, 100))
+
+        // make sure background task is enqueued
+        assertThat(fakeExecutor.numPending()).isEqualTo(1)
+
+        // make sure regionSamplingHelper will have empty Rect
+        whenever(fakeSamplingCallback.getSampledRegion(any())).thenReturn(Rect(0, 0, 0, 0))
+        regionSamplingHelper.onLayoutChange(sampledView, 0, 0, 0, 0, 0, 0, 0, 0)
+
+        // resume running of background thread
+        fakeExecutor.runAllReady()
+
+        // grab Rect passed into compositionSamplingListener and make sure it's not empty
+        val argumentGrabber = argumentCaptor<Rect>()
+        verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl),
+                argumentGrabber.capture())
+        assertThat(argumentGrabber.value.isEmpty).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
deleted file mode 100644
index 5432a74..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ /dev/null
@@ -1,88 +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;
-
-import static org.junit.Assert.assertFalse;
-
-import android.os.Handler;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.Dependency;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.shade.ShadeController;
-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.stack.NotificationListContainer;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-/**
- * Verifies that particular sets of dependencies don't have dependencies on others. For example,
- * code managing notifications shouldn't directly depend on CentralSurfaces, since there are
- * platforms which want to manage notifications, but don't use CentralSurfaces.
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-public class NonPhoneDependencyTest extends SysuiTestCase {
-    @Mock private NotificationPresenter mPresenter;
-    @Mock private NotificationListContainer mListContainer;
-    @Mock private RemoteInputController.Delegate mDelegate;
-    @Mock private NotificationRemoteInputManager.Callback mRemoteInputManagerCallback;
-    @Mock private OnSettingsClickListener mOnSettingsClickListener;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
-        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
-               new Handler(TestableLooper.get(this).getLooper()));
-    }
-
-    @Ignore("Causes binder calls which fail")
-    @Test
-    public void testNotificationManagementCodeHasNoDependencyOnStatusBarWindowManager() {
-        mDependency.injectMockDependency(ShadeController.class);
-        NotificationGutsManager gutsManager = Dependency.get(NotificationGutsManager.class);
-        NotificationLogger notificationLogger = Dependency.get(NotificationLogger.class);
-        NotificationMediaManager mediaManager = Dependency.get(NotificationMediaManager.class);
-        NotificationRemoteInputManager remoteInputManager =
-                Dependency.get(NotificationRemoteInputManager.class);
-        NotificationLockscreenUserManager lockscreenUserManager =
-                Dependency.get(NotificationLockscreenUserManager.class);
-        gutsManager.setUpWithPresenter(mPresenter, mListContainer,
-                mOnSettingsClickListener);
-        notificationLogger.setUpWithContainer(mListContainer);
-        mediaManager.setUpWithPresenter(mPresenter);
-        remoteInputManager.setUpWithCallback(mRemoteInputManagerCallback,
-                mDelegate);
-        lockscreenUserManager.setUpWithPresenter(mPresenter);
-
-        TestableLooper.get(this).processAllMessages();
-        assertFalse(mDependency.hasInstantiatedDependency(NotificationShadeWindowController.class));
-    }
-}
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 853d1df..bdafa48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -52,6 +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.recents.OverviewProxyService;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.NotificationStateChangedListener;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -88,6 +89,8 @@
     @Mock
     private NotificationClickNotifier mClickNotifier;
     @Mock
+    private OverviewProxyService mOverviewProxyService;
+    @Mock
     private KeyguardManager mKeyguardManager;
     @Mock
     private DeviceProvisionedController mDeviceProvisionedController;
@@ -344,6 +347,7 @@
                     (() -> mVisibilityProvider),
                     (() -> mNotifCollection),
                     mClickNotifier,
+                    (() -> mOverviewProxyService),
                     NotificationLockscreenUserManagerTest.this.mKeyguardManager,
                     mStatusBarStateController,
                     Handler.createAsync(Looper.myLooper()),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 9f21409..82e32b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.notification.collection;
 
 import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpTree;
+import static com.android.systemui.statusbar.notification.collection.ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -45,6 +46,7 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.util.ArrayMap;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -125,6 +127,10 @@
     private Map<String, Integer> mNextIdMap = new ArrayMap<>();
     private int mNextRank = 0;
 
+    private Log.TerribleFailureHandler mOldWtfHandler = null;
+    private Log.TerribleFailure mLastWtf = null;
+    private int mWtfCount = 0;
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -1748,14 +1754,17 @@
         mListBuilder.addPreGroupFilter(filter);
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the filter is invalidated exactly
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is NOT thrown.
+        // THEN an exception is NOT thrown directly, but a WTF IS logged.
+        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
     }
 
     @Test(expected = IllegalStateException.class)
@@ -1767,18 +1776,24 @@
         mListBuilder.addPreGroupFilter(filter);
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the filter is invalidated more than
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        try {
+            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        } finally {
+            expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        }
 
         // THEN an exception IS thrown.
     }
 
     @Test
-    public void testNonConsecutiveOutOfOrderInvalidationDontThrowAfterTooManyRuns() {
+    public void testNonConsecutiveOutOfOrderInvalidationsDontThrowAfterTooManyRuns() {
         // GIVEN a PreGroupNotifFilter that gets invalidated during the grouping stage,
         NotifFilter filter = new PackageFilter(PACKAGE_1);
         CountingInvalidator invalidator = new CountingInvalidator(filter);
@@ -1786,17 +1801,22 @@
         mListBuilder.addPreGroupFilter(filter);
         mListBuilder.addOnBeforeTransformGroupsListener(listener);
 
-        // WHEN we try to run the pipeline and the filter is invalidated at least
-        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
-        addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS);
-        dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS);
-        dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        interceptWtfs();
 
-        // THEN an exception is NOT thrown.
+        // WHEN we try to run the pipeline and the filter is invalidated
+        // MAX_CONSECUTIVE_REENTRANT_REBUILDS times, the pipeline runs for a non-reentrant reason,
+        // and then the filter is invalidated MAX_CONSECUTIVE_REENTRANT_REBUILDS times again,
+        addNotif(0, PACKAGE_2);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        dispatchBuild();
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        // Note: dispatchBuild itself triggers a non-reentrant pipeline run.
+        dispatchBuild();
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+
+        // THEN an exception is NOT thrown, but WTFs ARE logged.
+        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS * 2);
     }
 
     @Test
@@ -1808,14 +1828,18 @@
         mListBuilder.addPromoter(promoter);
         mListBuilder.addOnBeforeSortListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the promoter is invalidated exactly
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_1);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is NOT thrown.
+        // THEN an exception is NOT thrown directly, but a WTF IS logged.
+        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+
     }
 
     @Test(expected = IllegalStateException.class)
@@ -1827,12 +1851,18 @@
         mListBuilder.addPromoter(promoter);
         mListBuilder.addOnBeforeSortListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the promoter is invalidated more than
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_1);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        try {
+            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        } finally {
+            expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        }
 
         // THEN an exception IS thrown.
     }
@@ -1846,14 +1876,17 @@
         mListBuilder.setComparators(singletonList(comparator));
         mListBuilder.addOnBeforeRenderListListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the comparator is invalidated exactly
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is NOT thrown.
+        // THEN an exception is NOT thrown directly, but a WTF IS logged.
+        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
     }
 
     @Test(expected = IllegalStateException.class)
@@ -1865,12 +1898,14 @@
         mListBuilder.setComparators(singletonList(comparator));
         mListBuilder.addOnBeforeRenderListListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the comparator is invalidated more than
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
         // THEN an exception IS thrown.
     }
@@ -1884,14 +1919,17 @@
         mListBuilder.addFinalizeFilter(filter);
         mListBuilder.addOnBeforeRenderListListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the PreRenderFilter is invalidated exactly
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
 
-        // THEN an exception is NOT thrown.
+        // THEN an exception is NOT thrown directly, but a WTF IS logged.
+        expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
     }
 
     @Test(expected = IllegalStateException.class)
@@ -1903,16 +1941,59 @@
         mListBuilder.addFinalizeFilter(filter);
         mListBuilder.addOnBeforeRenderListListener(listener);
 
+        interceptWtfs();
+
         // WHEN we try to run the pipeline and the PreRenderFilter is invalidated more than
         // MAX_CONSECUTIVE_REENTRANT_REBUILDS times,
         addNotif(0, PACKAGE_2);
-        invalidator.setInvalidationCount(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
+        invalidator.setInvalidationCount(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 1);
         dispatchBuild();
-        runWhileScheduledUpTo(ShadeListBuilder.MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        try {
+            runWhileScheduledUpTo(MAX_CONSECUTIVE_REENTRANT_REBUILDS + 2);
+        } finally {
+            expectWtfs(MAX_CONSECUTIVE_REENTRANT_REBUILDS);
+        }
 
         // THEN an exception IS thrown.
     }
 
+    private void interceptWtfs() {
+        assertNull(mOldWtfHandler);
+
+        mLastWtf = null;
+        mWtfCount = 0;
+
+        mOldWtfHandler = Log.setWtfHandler((tag, e, system) -> {
+            Log.e("ShadeListBuilderTest", "Observed WTF: " + e);
+            mLastWtf = e;
+            mWtfCount++;
+        });
+    }
+
+    private void expectNoWtfs() {
+        assertNull(expectWtfs(0));
+    }
+
+    private Log.TerribleFailure expectWtf() {
+        return expectWtfs(1);
+    }
+
+    private Log.TerribleFailure expectWtfs(int expectedWtfCount) {
+        assertNotNull(mOldWtfHandler);
+
+        Log.setWtfHandler(mOldWtfHandler);
+        mOldWtfHandler = null;
+
+        Log.TerribleFailure wtf = mLastWtf;
+        int wtfCount = mWtfCount;
+
+        mLastWtf = null;
+        mWtfCount = 0;
+
+        assertEquals(expectedWtfCount, wtfCount);
+        return wtf;
+    }
+
     @Test
     public void testStableOrdering() {
         mStabilityManager.setAllowEntryReordering(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 2ee3126..2970807 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -337,6 +337,40 @@
     }
 
     @Test
+    fun testOnEntryUpdated_toAlert() {
+        // GIVEN that an entry is posted that should not heads up
+        setShouldHeadsUp(mEntry, false)
+        mCollectionListener.onEntryAdded(mEntry)
+
+        // WHEN it's updated to heads up
+        setShouldHeadsUp(mEntry)
+        mCollectionListener.onEntryUpdated(mEntry)
+        mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mEntry))
+        mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mEntry))
+
+        // THEN the notification alerts
+        finishBind(mEntry)
+        verify(mHeadsUpManager).showNotification(mEntry)
+    }
+
+    @Test
+    fun testOnEntryUpdated_toNotAlert() {
+        // GIVEN that an entry is posted that should heads up
+        setShouldHeadsUp(mEntry)
+        mCollectionListener.onEntryAdded(mEntry)
+
+        // WHEN it's updated to not heads up
+        setShouldHeadsUp(mEntry, false)
+        mCollectionListener.onEntryUpdated(mEntry)
+        mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mEntry))
+        mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mEntry))
+
+        // THEN the notification is never bound or shown
+        verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any())
+        verify(mHeadsUpManager, never()).showNotification(any())
+    }
+
+    @Test
     fun testOnEntryRemovedRemovesHeadsUpNotification() {
         // GIVEN the current HUN is mEntry
         addHUN(mEntry)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitorTest.kt
new file mode 100644
index 0000000..16e2441
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationMemoryMonitorTest.kt
@@ -0,0 +1,321 @@
+/*
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.logging
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.Person
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.drawable.Icon
+import android.testing.AndroidTestingRunner
+import android.widget.RemoteViews
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+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
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationMemoryMonitorTest : SysuiTestCase() {
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_plainNotification() {
+        val notification = createBasicNotification().build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 3316,
+            bigPicture = 0,
+            extender = 0,
+            style = null,
+            styleIcon = 0,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_plainNotification_dontDoubleCountSameBitmap() {
+        val icon = Icon.createWithBitmap(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888))
+        val notification = createBasicNotification().setLargeIcon(icon).setSmallIcon(icon).build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = 0,
+            extras = 3316,
+            bigPicture = 0,
+            extender = 0,
+            style = null,
+            styleIcon = 0,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_customViewNotification_marksTrue() {
+        val notification =
+            createBasicNotification()
+                .setCustomContentView(
+                    RemoteViews(context.packageName, android.R.layout.list_content)
+                )
+                .build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 3384,
+            bigPicture = 0,
+            extender = 0,
+            style = null,
+            styleIcon = 0,
+            hasCustomView = true,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_notificationWithDataIcon_calculatesCorrectly() {
+        val dataIcon = Icon.createWithData(ByteArray(444444), 0, 444444)
+        val notification =
+            createBasicNotification().setLargeIcon(dataIcon).setSmallIcon(dataIcon).build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = 444444,
+            largeIcon = 0,
+            extras = 3212,
+            bigPicture = 0,
+            extender = 0,
+            style = null,
+            styleIcon = 0,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_bigPictureStyle() {
+        val bigPicture =
+            Icon.createWithBitmap(Bitmap.createBitmap(600, 400, Bitmap.Config.ARGB_8888))
+        val bigPictureIcon =
+            Icon.createWithAdaptiveBitmap(Bitmap.createBitmap(386, 432, Bitmap.Config.ARGB_8888))
+        val notification =
+            createBasicNotification()
+                .setStyle(
+                    Notification.BigPictureStyle()
+                        .bigPicture(bigPicture)
+                        .bigLargeIcon(bigPictureIcon)
+                )
+                .build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 4092,
+            bigPicture = bigPicture.bitmap.allocationByteCount,
+            extender = 0,
+            style = "BigPictureStyle",
+            styleIcon = bigPictureIcon.bitmap.allocationByteCount,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_callingStyle() {
+        val personIcon =
+            Icon.createWithBitmap(Bitmap.createBitmap(386, 432, Bitmap.Config.ARGB_8888))
+        val person = Person.Builder().setIcon(personIcon).setName("Person").build()
+        val fakeIntent =
+            PendingIntent.getActivity(context, 0, Intent(), PendingIntent.FLAG_IMMUTABLE)
+        val notification =
+            createBasicNotification()
+                .setStyle(Notification.CallStyle.forIncomingCall(person, fakeIntent, fakeIntent))
+                .build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 4084,
+            bigPicture = 0,
+            extender = 0,
+            style = "CallStyle",
+            styleIcon = personIcon.bitmap.allocationByteCount,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_messagingStyle() {
+        val personIcon =
+            Icon.createWithBitmap(Bitmap.createBitmap(386, 432, Bitmap.Config.ARGB_8888))
+        val person = Person.Builder().setIcon(personIcon).setName("Person").build()
+        val message = Notification.MessagingStyle.Message("Message!", 4323, person)
+        val historicPersonIcon =
+            Icon.createWithBitmap(Bitmap.createBitmap(348, 382, Bitmap.Config.ARGB_8888))
+        val historicPerson =
+            Person.Builder().setIcon(historicPersonIcon).setName("Historic person").build()
+        val historicMessage =
+            Notification.MessagingStyle.Message("Historic message!", 5848, historicPerson)
+
+        val notification =
+            createBasicNotification()
+                .setStyle(
+                    Notification.MessagingStyle(person)
+                        .addMessage(message)
+                        .addHistoricMessage(historicMessage)
+                )
+                .build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 5024,
+            bigPicture = 0,
+            extender = 0,
+            style = "MessagingStyle",
+            styleIcon =
+                personIcon.bitmap.allocationByteCount +
+                    historicPersonIcon.bitmap.allocationByteCount,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_carExtender() {
+        val carIcon = Bitmap.createBitmap(432, 322, Bitmap.Config.ARGB_8888)
+        val extender = Notification.CarExtender().setLargeIcon(carIcon)
+        val notification = createBasicNotification().extend(extender).build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 3612,
+            bigPicture = 0,
+            extender = 556656,
+            style = null,
+            styleIcon = 0,
+            hasCustomView = false,
+        )
+    }
+
+    @Test
+    fun currentNotificationMemoryUse_tvWearExtender() {
+        val tvExtender = Notification.TvExtender().setChannel("channel2")
+        val wearBackground = Bitmap.createBitmap(443, 433, Bitmap.Config.ARGB_8888)
+        val wearExtender = Notification.WearableExtender().setBackground(wearBackground)
+        val notification = createBasicNotification().extend(tvExtender).extend(wearExtender).build()
+        val nmm = createNMMWithNotifications(listOf(notification))
+        val memoryUse = getUseObject(nmm.currentNotificationMemoryUse())
+        assertNotificationObjectSizes(
+            memoryUse = memoryUse,
+            smallIcon = notification.smallIcon.bitmap.allocationByteCount,
+            largeIcon = notification.getLargeIcon().bitmap.allocationByteCount,
+            extras = 3820,
+            bigPicture = 0,
+            extender = 388 + wearBackground.allocationByteCount,
+            style = null,
+            styleIcon = 0,
+            hasCustomView = false,
+        )
+    }
+
+    private fun createBasicNotification(): Notification.Builder {
+        val smallIcon =
+            Icon.createWithBitmap(Bitmap.createBitmap(250, 250, Bitmap.Config.ARGB_8888))
+        val largeIcon =
+            Icon.createWithBitmap(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888))
+        return Notification.Builder(context)
+            .setSmallIcon(smallIcon)
+            .setLargeIcon(largeIcon)
+            .setContentTitle("This is a title")
+            .setContentText("This is content text.")
+    }
+
+    /** This will generate a nicer error message than comparing objects */
+    private fun assertNotificationObjectSizes(
+        memoryUse: NotificationMemoryUsage,
+        smallIcon: Int,
+        largeIcon: Int,
+        extras: Int,
+        bigPicture: Int,
+        extender: Int,
+        style: String?,
+        styleIcon: Int,
+        hasCustomView: Boolean
+    ) {
+        assertThat(memoryUse.packageName).isEqualTo("test_pkg")
+        assertThat(memoryUse.notificationId)
+            .isEqualTo(NotificationUtils.logKey("0|test_pkg|0|test|0"))
+        assertThat(memoryUse.objectUsage.smallIcon).isEqualTo(smallIcon)
+        assertThat(memoryUse.objectUsage.largeIcon).isEqualTo(largeIcon)
+        assertThat(memoryUse.objectUsage.bigPicture).isEqualTo(bigPicture)
+        if (style == null) {
+            assertThat(memoryUse.objectUsage.style).isNull()
+        } else {
+            assertThat(memoryUse.objectUsage.style).isEqualTo(style)
+        }
+        assertThat(memoryUse.objectUsage.styleIcon).isEqualTo(styleIcon)
+        assertThat(memoryUse.objectUsage.hasCustomView).isEqualTo(hasCustomView)
+    }
+
+    private fun getUseObject(
+        singleItemUseList: List<NotificationMemoryUsage>
+    ): NotificationMemoryUsage {
+        assertThat(singleItemUseList).hasSize(1)
+        return singleItemUseList[0]
+    }
+
+    private fun createNMMWithNotifications(
+        notifications: List<Notification>
+    ): NotificationMemoryMonitor {
+        val notifPipeline: NotifPipeline = mock()
+        val notificationEntries =
+            notifications.map { n ->
+                NotificationEntryBuilder().setTag("test").setNotification(n).build()
+            }
+        whenever(notifPipeline.allNotifs).thenReturn(notificationEntries)
+        return NotificationMemoryMonitor(notifPipeline, mock())
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
index 7e97629..dae0aa2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
@@ -40,6 +40,10 @@
                 NotificationPanelLogger.toNotificationProto(visibleNotifications)));
     }
 
+    @Override
+    public void logNotificationDrag(NotificationEntry draggedNotification) {
+    }
+
     public static class CallRecord {
         public boolean isLockscreen;
         public Notifications.NotificationList list;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index 922e93d..ed2afe7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -40,6 +40,8 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
@@ -63,6 +65,7 @@
     private NotificationMenuRowPlugin.MenuItem mMenuItem =
             mock(NotificationMenuRowPlugin.MenuItem.class);
     private ShadeController mShadeController = mock(ShadeController.class);
+    private NotificationPanelLogger mNotificationPanelLogger = mock(NotificationPanelLogger.class);
 
     @Before
     public void setUp() throws Exception {
@@ -82,7 +85,7 @@
         when(mMenuRow.getLongpressMenuItem(any(Context.class))).thenReturn(mMenuItem);
 
         mController = new ExpandableNotificationRowDragController(mContext, mHeadsUpManager,
-                mShadeController);
+                mShadeController, mNotificationPanelLogger);
     }
 
     @Test
@@ -96,6 +99,7 @@
         mRow.doDragCallback(0, 0);
         verify(controller).startDragAndDrop(mRow);
         verify(mHeadsUpManager, times(1)).releaseAllImmediately();
+        verify(mNotificationPanelLogger, times(1)).logNotificationDrag(any());
     }
 
     @Test
@@ -107,6 +111,7 @@
         verify(controller).startDragAndDrop(mRow);
         verify(mShadeController).animateCollapsePanels(eq(0), eq(true),
                 eq(false), anyFloat());
+        verify(mNotificationPanelLogger, times(1)).logNotificationDrag(any());
     }
 
     @Test
@@ -124,6 +129,7 @@
 
         // Verify that we never start the actual drag since there is no content
         verify(mRow, never()).startDragAndDrop(any(), any(), any(), anyInt());
+        verify(mNotificationPanelLogger, never()).logNotificationDrag(any());
     }
 
     private ExpandableNotificationRowDragController createSpyController() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index 682ff1f..81b8e98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -32,6 +32,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
+import com.android.internal.widget.NotificationActionListLayout;
 import com.android.internal.widget.NotificationExpandButton;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
@@ -142,4 +143,60 @@
         verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
         verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
     }
+
+    @Test
+    @UiThreadTest
+    public void testRemoteInputVisibleSetsActionsUnimportantHideDescendantsForAccessibility() {
+        View mockContracted = mock(NotificationHeaderView.class);
+
+        View mockExpandedActions = mock(NotificationActionListLayout.class);
+        View mockExpanded = mock(NotificationHeaderView.class);
+        when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
+                mockExpandedActions);
+
+        View mockHeadsUpActions = mock(NotificationActionListLayout.class);
+        View mockHeadsUp = mock(NotificationHeaderView.class);
+        when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
+                mockHeadsUpActions);
+
+        mView.setContractedChild(mockContracted);
+        mView.setExpandedChild(mockExpanded);
+        mView.setHeadsUpChild(mockHeadsUp);
+
+        mView.setRemoteInputVisible(true);
+
+        verify(mockContracted, times(0)).findViewById(0);
+        verify(mockExpandedActions, times(1)).setImportantForAccessibility(
+                View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+        verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
+                View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testRemoteInputInvisibleSetsActionsAutoImportantForAccessibility() {
+        View mockContracted = mock(NotificationHeaderView.class);
+
+        View mockExpandedActions = mock(NotificationActionListLayout.class);
+        View mockExpanded = mock(NotificationHeaderView.class);
+        when(mockExpanded.findViewById(com.android.internal.R.id.actions)).thenReturn(
+                mockExpandedActions);
+
+        View mockHeadsUpActions = mock(NotificationActionListLayout.class);
+        View mockHeadsUp = mock(NotificationHeaderView.class);
+        when(mockHeadsUp.findViewById(com.android.internal.R.id.actions)).thenReturn(
+                mockHeadsUpActions);
+
+        mView.setContractedChild(mockContracted);
+        mView.setExpandedChild(mockExpanded);
+        mView.setHeadsUpChild(mockHeadsUp);
+
+        mView.setRemoteInputVisible(false);
+
+        verify(mockContracted, times(0)).findViewById(0);
+        verify(mockExpandedActions, times(1)).setImportantForAccessibility(
+                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        verify(mockHeadsUpActions, times(1)).setImportantForAccessibility(
+                View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+    }
 }
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 8be9eb5..1c9b0be 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
@@ -45,6 +45,7 @@
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.media.KeyguardMediaController;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
@@ -127,6 +128,7 @@
     @Mock private NotificationStackScrollLogger mLogger;
     @Mock private NotificationStackSizeCalculator mNotificationStackSizeCalculator;
     @Mock private ShadeTransitionController mShadeTransitionController;
+    @Mock private FeatureFlags mFeatureFlags;
 
     @Captor
     private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
@@ -174,7 +176,8 @@
                 mJankMonitor,
                 mStackLogger,
                 mLogger,
-                mNotificationStackSizeCalculator
+                mNotificationStackSizeCalculator,
+                mFeatureFlags
         );
 
         when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
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 6ae021b..4353036 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
@@ -55,6 +55,7 @@
 import androidx.test.annotation.UiThreadTest;
 import androidx.test.filters.SmallTest;
 
+import com.android.keyguard.BouncerPanelExpansionCalculator;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -179,6 +180,40 @@
     }
 
     @Test
+    public void testUpdateStackHeight_qsExpansionGreaterThanZero() {
+        final float expansionFraction = 0.2f;
+        final float overExpansion = 50f;
+
+        mStackScroller.setQsExpansionFraction(1f);
+        mAmbientState.setExpansionFraction(expansionFraction);
+        mAmbientState.setOverExpansion(overExpansion);
+        when(mAmbientState.isBouncerInTransit()).thenReturn(true);
+
+
+        mStackScroller.setExpandedHeight(100f);
+
+        float expected = MathUtils.lerp(0, overExpansion,
+                BouncerPanelExpansionCalculator.aboutToShowBouncerProgress(expansionFraction));
+        assertThat(mAmbientState.getStackY()).isEqualTo(expected);
+    }
+
+    @Test
+    public void testUpdateStackHeight_qsExpansionZero() {
+        final float expansionFraction = 0.2f;
+        final float overExpansion = 50f;
+
+        mStackScroller.setQsExpansionFraction(0f);
+        mAmbientState.setExpansionFraction(expansionFraction);
+        mAmbientState.setOverExpansion(overExpansion);
+        when(mAmbientState.isBouncerInTransit()).thenReturn(true);
+
+        mStackScroller.setExpandedHeight(100f);
+
+        float expected = MathUtils.lerp(0, overExpansion, expansionFraction);
+        assertThat(mAmbientState.getStackY()).isEqualTo(expected);
+    }
+
+    @Test
     public void testUpdateStackHeight_withDozeAmount_whenDozeChanging() {
         final float dozeAmount = 0.5f;
         mAmbientState.setDozeAmount(dozeAmount);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index 1305d79..4ea1c71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -18,10 +18,13 @@
 import static junit.framework.Assert.assertTrue;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 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.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -51,10 +54,15 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.mockito.stubbing.Answer;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
 /**
  * Tests for {@link NotificationSwipeHelper}.
  */
@@ -74,7 +82,11 @@
     private Runnable mFalsingCheck;
     private FeatureFlags mFeatureFlags;
 
-    @Rule public MockitoRule mockito = MockitoJUnit.rule();
+    private static final int FAKE_ROW_WIDTH = 20;
+    private static final int FAKE_ROW_HEIGHT = 20;
+
+    @Rule
+    public MockitoRule mockito = MockitoJUnit.rule();
 
     @Before
     public void setUp() throws Exception {
@@ -444,8 +456,8 @@
         doReturn(5f).when(mEvent).getRawX();
         doReturn(10f).when(mEvent).getRawY();
 
-        doReturn(20).when(mView).getWidth();
-        doReturn(20).when(mView).getHeight();
+        doReturn(FAKE_ROW_WIDTH).when(mView).getWidth();
+        doReturn(FAKE_ROW_HEIGHT).when(mView).getHeight();
 
         Answer answer = (Answer) invocation -> {
             int[] arr = invocation.getArgument(0);
@@ -472,8 +484,8 @@
         doReturn(5f).when(mEvent).getRawX();
         doReturn(10f).when(mEvent).getRawY();
 
-        doReturn(20).when(mNotificationRow).getWidth();
-        doReturn(20).when(mNotificationRow).getActualHeight();
+        doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getWidth();
+        doReturn(FAKE_ROW_HEIGHT).when(mNotificationRow).getActualHeight();
 
         Answer answer = (Answer) invocation -> {
             int[] arr = invocation.getArgument(0);
@@ -491,4 +503,56 @@
         assertFalse("Touch is not within the view",
                 mSwipeHelper.isTouchInView(mEvent, mNotificationRow));
     }
+
+    @Test
+    public void testContentAlphaRemainsUnchangedWhenNotificationIsNotDismissible() {
+        doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
+
+        mSwipeHelper.onTranslationUpdate(mNotificationRow, 12, false);
+
+        verify(mNotificationRow, never()).setContentAlpha(anyFloat());
+    }
+
+    @Test
+    public void testContentAlphaRemainsUnchangedWhenFeatureFlagIsDisabled() {
+
+        // Returning true prevents alpha fade. In an unmocked scenario the callback is instantiated
+        // within NotificationStackScrollLayoutController and returns the inverted value of the
+        // feature flag
+        doReturn(true).when(mCallback).updateSwipeProgress(any(), anyBoolean(), anyFloat());
+        doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
+
+        mSwipeHelper.onTranslationUpdate(mNotificationRow, 12, true);
+
+        verify(mNotificationRow, never()).setContentAlpha(anyFloat());
+    }
+
+    @Test
+    public void testContentAlphaFadeAnimationSpecs() {
+        // The alpha fade should be linear from 1f to 0f as translation progresses from 0 to 60% of
+        // view-width, and 0f at translations higher than that.
+        doReturn(FAKE_ROW_WIDTH).when(mNotificationRow).getMeasuredWidth();
+
+        List<Integer> translations = Arrays.asList(
+                -FAKE_ROW_WIDTH * 2,
+                -FAKE_ROW_WIDTH,
+                (int) (-FAKE_ROW_WIDTH * 0.3),
+                0,
+                (int) (FAKE_ROW_WIDTH * 0.3),
+                (int) (FAKE_ROW_WIDTH * 0.6),
+                FAKE_ROW_WIDTH,
+                FAKE_ROW_WIDTH * 2);
+        List<Float> expectedAlphas = translations.stream().map(translation ->
+                        mSwipeHelper.getSwipeAlpha(Math.abs((float) translation / FAKE_ROW_WIDTH)))
+                .collect(Collectors.toList());
+
+        for (Integer translation : translations) {
+            mSwipeHelper.onTranslationUpdate(mNotificationRow, translation, true);
+        }
+
+        ArgumentCaptor<Float> capturedValues = ArgumentCaptor.forClass(Float.class);
+        verify(mNotificationRow, times(translations.size())).setContentAlpha(
+                capturedValues.capture());
+        assertEquals(expectedAlphas, capturedValues.getAllValues());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
new file mode 100644
index 0000000..da543d4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ViewStateTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 android.util.Log
+import android.util.Log.TerribleFailureHandler
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import kotlin.math.log2
+import kotlin.math.sqrt
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class ViewStateTest : SysuiTestCase() {
+    private val viewState = ViewState()
+
+    private var wtfHandler: TerribleFailureHandler? = null
+    private var wtfCount = 0
+
+    @Suppress("DIVISION_BY_ZERO")
+    @Test
+    fun testWtfs() {
+        interceptWtfs()
+
+        // Setting valid values doesn't cause any wtfs.
+        viewState.alpha = 0.1f
+        viewState.xTranslation = 0f
+        viewState.yTranslation = 10f
+        viewState.zTranslation = 20f
+        viewState.scaleX = 0.5f
+        viewState.scaleY = 0.25f
+
+        expectWtfs(0)
+
+        // Setting NaN values leads to wtfs being logged, and the value not being changed.
+        viewState.alpha = 0.0f / 0.0f
+        expectWtfs(1)
+        Assert.assertEquals(viewState.alpha, 0.1f)
+
+        viewState.xTranslation = Float.NaN
+        expectWtfs(2)
+        Assert.assertEquals(viewState.xTranslation, 0f)
+
+        viewState.yTranslation = log2(-10.0).toFloat()
+        expectWtfs(3)
+        Assert.assertEquals(viewState.yTranslation, 10f)
+
+        viewState.zTranslation = sqrt(-1.0).toFloat()
+        expectWtfs(4)
+        Assert.assertEquals(viewState.zTranslation, 20f)
+
+        viewState.scaleX = Float.POSITIVE_INFINITY + Float.NEGATIVE_INFINITY
+        expectWtfs(5)
+        Assert.assertEquals(viewState.scaleX, 0.5f)
+
+        viewState.scaleY = Float.POSITIVE_INFINITY * 0
+        expectWtfs(6)
+        Assert.assertEquals(viewState.scaleY, 0.25f)
+    }
+
+    private fun interceptWtfs() {
+        wtfCount = 0
+        wtfHandler =
+            Log.setWtfHandler { _: String?, e: Log.TerribleFailure, _: Boolean ->
+                Log.e("ViewStateTest", "Observed WTF: $e")
+                wtfCount++
+            }
+    }
+
+    private fun expectWtfs(expectedWtfCount: Int) {
+        Assert.assertNotNull(wtfHandler)
+        Assert.assertEquals(expectedWtfCount, wtfCount)
+    }
+}
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 9de9db1..996851e 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
@@ -40,7 +40,6 @@
 import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
-import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.NotificationShadeWindowViewController;
@@ -73,7 +72,6 @@
     @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
-    @Mock private KeyguardViewMediator mKeyguardViewMediator;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
     @Mock private BatteryController mBatteryController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -101,7 +99,7 @@
         mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle,
                 mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
                 mBatteryController, mScrimController, () -> mBiometricUnlockController,
-                mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
+                () -> mAssistManager, mDozeScrimController,
                 mKeyguardUpdateMonitor, mPulseExpansionHandler,
                 mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
                 mAuthController, mNotificationIconAreaController);
@@ -132,19 +130,11 @@
         verify(mStatusBarStateController).setIsDozing(eq(false));
     }
 
-
     @Test
     public void testPulseWhileDozing_updatesScrimController() {
         mCentralSurfaces.setBarStateForTest(StatusBarState.KEYGUARD);
         mCentralSurfaces.showKeyguardImpl();
 
-        // Keep track of callback to be able to stop the pulse
-//        DozeHost.PulseCallback[] pulseCallback = new DozeHost.PulseCallback[1];
-//        doAnswer(invocation -> {
-//            pulseCallback[0] = invocation.getArgument(0);
-//            return null;
-//        }).when(mDozeScrimController).pulse(any(), anyInt());
-
         // Starting a pulse should change the scrim controller to the pulsing state
         mDozeServiceHost.pulseWhileDozing(new DozeHost.PulseCallback() {
             @Override
@@ -210,4 +200,17 @@
             }
         }
     }
+
+    @Test
+    public void testStopPulsing_setPendingPulseToFalse() {
+        // GIVEN a pending pulse
+        mDozeServiceHost.setPulsePending(true);
+
+        // WHEN pulsing is stopped
+        mDozeServiceHost.stopPulsing();
+
+        // THEN isPendingPulse=false, pulseOutNow is called
+        assertFalse(mDozeServiceHost.isPulsePending());
+        verify(mDozeScrimController).pulseOutNow();
+    }
 }
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 ba5f503..6ec5cf8 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
@@ -47,6 +47,7 @@
 import com.android.keyguard.CarrierTextController;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardLogger;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.battery.BatteryMeterViewController;
@@ -123,6 +124,7 @@
     private StatusBarUserInfoTracker mStatusBarUserInfoTracker;
     @Mock private SecureSettings mSecureSettings;
     @Mock private CommandQueue mCommandQueue;
+    @Mock private KeyguardLogger mLogger;
 
     private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
     private KeyguardStatusBarView mKeyguardStatusBarView;
@@ -135,7 +137,7 @@
 
         MockitoAnnotations.initMocks(this);
 
-        when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
+        when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
 
         allowTestableLooperAsMainThread();
         TestableLooper.get(this).runWithLooper(() -> {
@@ -172,7 +174,8 @@
                 mStatusBarUserInfoTracker,
                 mSecureSettings,
                 mCommandQueue,
-                mFakeExecutor
+                mFakeExecutor,
+                mLogger
         );
     }
 
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 de7db74..9c56c26 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
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
 import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
+import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter;
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel;
 import com.android.systemui.utils.leaks.LeakCheckedTest;
 
@@ -51,8 +52,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import javax.inject.Provider;
-
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -79,8 +78,10 @@
         LinearLayout layout = new LinearLayout(mContext);
         TestDarkIconManager manager = new TestDarkIconManager(
                 layout,
+                StatusBarLocation.HOME,
                 mock(StatusBarPipelineFlags.class),
-                () -> mock(WifiViewModel.class),
+                mock(WifiViewModel.class),
+                mock(MobileUiAdapter.class),
                 mMobileContextProvider,
                 mock(DarkIconDispatcher.class));
         testCallOnAdd_forManager(manager);
@@ -121,13 +122,17 @@
 
         TestDarkIconManager(
                 LinearLayout group,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
+                WifiViewModel wifiViewModel,
+                MobileUiAdapter mobileUiAdapter,
                 MobileContextProvider contextProvider,
                 DarkIconDispatcher darkIconDispatcher) {
             super(group,
+                    location,
                     statusBarPipelineFlags,
-                    wifiViewModelProvider,
+                    wifiViewModel,
+                    mobileUiAdapter,
                     contextProvider,
                     darkIconDispatcher);
         }
@@ -165,8 +170,10 @@
     private static class TestIconManager extends IconManager implements TestableIconManager {
         TestIconManager(ViewGroup group, MobileContextProvider contextProvider) {
             super(group,
+                    StatusBarLocation.HOME,
                     mock(StatusBarPipelineFlags.class),
-                    () -> mock(WifiViewModel.class),
+                    mock(WifiViewModel.class),
+                    mock(MobileUiAdapter.class),
                     contextProvider);
         }
 
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 ee4b9d9c..04ad1f8 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
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static com.android.systemui.flags.Flags.MODERN_BOUNCER;
+
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -26,7 +28,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -34,6 +35,10 @@
 import android.testing.TestableLooper;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
+import android.window.WindowOnBackInvokedDispatcher;
 
 import androidx.test.filters.SmallTest;
 
@@ -72,6 +77,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -118,6 +124,12 @@
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private KeyguardBouncer.BouncerExpansionCallback mBouncerExpansionCallback;
 
+    @Mock private ViewRootImpl mViewRootImpl;
+    @Mock private WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
+    @Captor
+    private ArgumentCaptor<OnBackInvokedCallback> mOnBackInvokedCallback;
+
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -153,7 +165,14 @@
                         mFeatureFlags,
                         mBouncerCallbackInteractor,
                         mBouncerInteractor,
-                        mBouncerView);
+                        mBouncerView) {
+                    @Override
+                    public ViewRootImpl getViewRootImpl() {
+                        return mViewRootImpl;
+                    }
+                };
+        when(mViewRootImpl.getOnBackInvokedDispatcher())
+                .thenReturn(mOnBackInvokedDispatcher);
         mStatusBarKeyguardViewManager.registerCentralSurfaces(
                 mCentralSurfaces,
                 mNotificationPanelView,
@@ -508,6 +527,37 @@
     }
 
     @Test
+    public void testPredictiveBackCallback_registration() {
+        /* verify that a predictive back callback is registered when the bouncer becomes visible */
+        mBouncerExpansionCallback.onVisibilityChanged(true);
+        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+                mOnBackInvokedCallback.capture());
+
+        /* verify that the same callback is unregistered when the bouncer becomes invisible */
+        mBouncerExpansionCallback.onVisibilityChanged(false);
+        verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(
+                eq(mOnBackInvokedCallback.getValue()));
+    }
+
+    @Test
+    public void testPredictiveBackCallback_invocationHidesBouncer() {
+        mBouncerExpansionCallback.onVisibilityChanged(true);
+        /* capture the predictive back callback during registration */
+        verify(mOnBackInvokedDispatcher).registerOnBackInvokedCallback(
+                eq(OnBackInvokedDispatcher.PRIORITY_OVERLAY),
+                mOnBackInvokedCallback.capture());
+
+        when(mBouncer.isShowing()).thenReturn(true);
+        when(mCentralSurfaces.shouldKeyguardHideImmediately()).thenReturn(true);
+        /* invoke the back callback directly */
+        mOnBackInvokedCallback.getValue().onBackInvoked();
+
+        /* verify that the bouncer will be hidden as a result of the invocation */
+        verify(mCentralSurfaces).setBouncerShowing(eq(false));
+    }
+
+    @Test
     public void testReportBouncerOnDreamWhenVisible() {
         mBouncerExpansionCallback.onVisibilityChanged(true);
         verify(mCentralSurfaces).setBouncerShowingOverDream(false);
@@ -528,19 +578,9 @@
     }
 
     @Test
-    public void testSetDozing_Dozing() {
-        clearInvocations(mBouncer);
-        mStatusBarKeyguardViewManager.onDozingChanged(true);
-        // Once when shown and once with dozing changed.
-        verify(mBouncer, times(1)).hide(false);
-    }
-
-    @Test
-    public void testSetDozing_notDozing() {
-        mStatusBarKeyguardViewManager.onDozingChanged(true);
-        clearInvocations(mBouncer);
-        mStatusBarKeyguardViewManager.onDozingChanged(false);
-        // Once when shown and twice with dozing changed.
-        verify(mBouncer, times(1)).hide(false);
+    public void flag_off_DoesNotCallBouncerInteractor() {
+        when(mFeatureFlags.isEnabled(MODERN_BOUNCER)).thenReturn(false);
+        mStatusBarKeyguardViewManager.hideBouncer(false);
+        verify(mBouncerInteractor, never()).hide();
     }
 }
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 37c8f62..a3c6e95 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
@@ -431,7 +431,7 @@
         mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
         when(mOperatorNameViewControllerFactory.create(any()))
                 .thenReturn(mOperatorNameViewController);
-        when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
+        when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
         mSecureSettings = mock(SecureSettings.class);
 
         setUpNotificationIconAreaController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileSubscriptionRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileSubscriptionRepository.kt
new file mode 100644
index 0000000..0d15268
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileSubscriptionRepository.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.data.repository
+
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeMobileSubscriptionRepository : MobileSubscriptionRepository {
+    private val _subscriptionsFlow = MutableStateFlow<List<SubscriptionInfo>>(listOf())
+    override val subscriptionsFlow: Flow<List<SubscriptionInfo>> = _subscriptionsFlow
+
+    private val _activeMobileDataSubscriptionId =
+        MutableStateFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+    override val activeMobileDataSubscriptionId = _activeMobileDataSubscriptionId
+
+    private val subIdFlows = mutableMapOf<Int, MutableStateFlow<MobileSubscriptionModel>>()
+    override fun getFlowForSubId(subId: Int): Flow<MobileSubscriptionModel> {
+        return subIdFlows[subId]
+            ?: MutableStateFlow(MobileSubscriptionModel()).also { subIdFlows[subId] = it }
+    }
+
+    fun setSubscriptions(subs: List<SubscriptionInfo>) {
+        _subscriptionsFlow.value = subs
+    }
+
+    fun setActiveMobileDataSubscriptionId(subId: Int) {
+        _activeMobileDataSubscriptionId.value = subId
+    }
+
+    fun setMobileSubscriptionModel(model: MobileSubscriptionModel, subId: Int) {
+        val subscription = subIdFlows[subId] ?: throw Exception("no flow exists for this subId yet")
+        subscription.value = model
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
new file mode 100644
index 0000000..6c495c5
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Defaults to `true` */
+class FakeUserSetupRepository : UserSetupRepository {
+    private val _isUserSetup: MutableStateFlow<Boolean> = MutableStateFlow(true)
+    override val isUserSetupFlow: Flow<Boolean> = _isUserSetup
+
+    fun setUserSetup(setup: Boolean) {
+        _isUserSetup.value = setup
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepositoryTest.kt
new file mode 100644
index 0000000..316b795
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileSubscriptionRepositoryTest.kt
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.data.repository
+
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyCallback.CarrierNetworkListener
+import android.telephony.TelephonyCallback.DataActivityListener
+import android.telephony.TelephonyCallback.DataConnectionStateListener
+import android.telephony.TelephonyCallback.DisplayInfoListener
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyCallback.SignalStrengthsListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+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 org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+class MobileSubscriptionRepositoryTest : SysuiTestCase() {
+    private lateinit var underTest: MobileSubscriptionRepositoryImpl
+
+    @Mock private lateinit var subscriptionManager: SubscriptionManager
+    @Mock private lateinit var telephonyManager: TelephonyManager
+    private val scope = CoroutineScope(IMMEDIATE)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        underTest =
+            MobileSubscriptionRepositoryImpl(
+                subscriptionManager,
+                telephonyManager,
+                IMMEDIATE,
+                scope,
+            )
+    }
+
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
+
+    @Test
+    fun testSubscriptions_initiallyEmpty() =
+        runBlocking(IMMEDIATE) {
+            assertThat(underTest.subscriptionsFlow.value).isEqualTo(listOf<SubscriptionInfo>())
+        }
+
+    @Test
+    fun testSubscriptions_listUpdates() =
+        runBlocking(IMMEDIATE) {
+            var latest: List<SubscriptionInfo>? = null
+
+            val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this)
+
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
+
+            job.cancel()
+        }
+
+    @Test
+    fun testSubscriptions_removingSub_updatesList() =
+        runBlocking(IMMEDIATE) {
+            var latest: List<SubscriptionInfo>? = null
+
+            val job = underTest.subscriptionsFlow.onEach { latest = it }.launchIn(this)
+
+            // WHEN 2 networks show up
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_1, SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // WHEN one network is removed
+            whenever(subscriptionManager.completeActiveSubscriptionInfoList)
+                .thenReturn(listOf(SUB_2))
+            getSubscriptionCallback().onSubscriptionsChanged()
+
+            // THEN the subscriptions list represents the newest change
+            assertThat(latest).isEqualTo(listOf(SUB_2))
+
+            job.cancel()
+        }
+
+    @Test
+    fun testActiveDataSubscriptionId_initialValueIsInvalidId() =
+        runBlocking(IMMEDIATE) {
+            assertThat(underTest.activeMobileDataSubscriptionId.value)
+                .isEqualTo(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+        }
+
+    @Test
+    fun testActiveDataSubscriptionId_updates() =
+        runBlocking(IMMEDIATE) {
+            var active: Int? = null
+
+            val job = underTest.activeMobileDataSubscriptionId.onEach { active = it }.launchIn(this)
+
+            getActiveDataSubscriptionCallback().onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+            assertThat(active).isEqualTo(SUB_2_ID)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_default() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(MobileSubscriptionModel())
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_emergencyOnly() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val serviceState = ServiceState()
+            serviceState.isEmergencyOnly = true
+
+            getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+
+            assertThat(latest?.isEmergencyOnly).isEqualTo(true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_emergencyOnly_toggles() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<ServiceStateListener>()
+            val serviceState = ServiceState()
+            serviceState.isEmergencyOnly = true
+            callback.onServiceStateChanged(serviceState)
+            serviceState.isEmergencyOnly = false
+            callback.onServiceStateChanged(serviceState)
+
+            assertThat(latest?.isEmergencyOnly).isEqualTo(false)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_signalStrengths_levelsUpdate() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<SignalStrengthsListener>()
+            val strength = signalStrength(1, 2, true)
+            callback.onSignalStrengthsChanged(strength)
+
+            assertThat(latest?.isGsm).isEqualTo(true)
+            assertThat(latest?.primaryLevel).isEqualTo(1)
+            assertThat(latest?.cdmaLevel).isEqualTo(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_dataConnectionState() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<DataConnectionStateListener>()
+            callback.onDataConnectionStateChanged(100, 200 /* unused */)
+
+            assertThat(latest?.dataConnectionState).isEqualTo(100)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_dataActivity() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<DataActivityListener>()
+            callback.onDataActivity(3)
+
+            assertThat(latest?.dataActivityDirection).isEqualTo(3)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_carrierNetworkChange() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<CarrierNetworkListener>()
+            callback.onCarrierNetworkChange(true)
+
+            assertThat(latest?.carrierNetworkChangeActive).isEqualTo(true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_displayInfo() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            val callback = getTelephonyCallbackForType<DisplayInfoListener>()
+            val ti = mock<TelephonyDisplayInfo>()
+            callback.onDisplayInfoChanged(ti)
+
+            assertThat(latest?.displayInfo).isEqualTo(ti)
+
+            job.cancel()
+        }
+
+    @Test
+    fun testFlowForSubId_isCached() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            val state1 = underTest.getFlowForSubId(SUB_1_ID)
+            val state2 = underTest.getFlowForSubId(SUB_1_ID)
+
+            assertThat(state1).isEqualTo(state2)
+        }
+
+    @Test
+    fun testFlowForSubId_isRemovedAfterFinish() =
+        runBlocking(IMMEDIATE) {
+            whenever(telephonyManager.createForSubscriptionId(any())).thenReturn(telephonyManager)
+
+            var latest: MobileSubscriptionModel? = null
+
+            // Start collecting on some flow
+            val job = underTest.getFlowForSubId(SUB_1_ID).onEach { latest = it }.launchIn(this)
+
+            // There should be once cached flow now
+            assertThat(underTest.getSubIdFlowCache().size).isEqualTo(1)
+
+            // When the job is canceled, the cache should be cleared
+            job.cancel()
+
+            assertThat(underTest.getSubIdFlowCache().size).isEqualTo(0)
+        }
+
+    private fun getSubscriptionCallback(): SubscriptionManager.OnSubscriptionsChangedListener {
+        val callbackCaptor = argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
+        verify(subscriptionManager)
+            .addOnSubscriptionsChangedListener(any(), callbackCaptor.capture())
+        return callbackCaptor.value!!
+    }
+
+    private fun getActiveDataSubscriptionCallback(): ActiveDataSubscriptionIdListener =
+        getTelephonyCallbackForType()
+
+    private fun getTelephonyCallbacks(): List<TelephonyCallback> {
+        val callbackCaptor = argumentCaptor<TelephonyCallback>()
+        verify(telephonyManager).registerTelephonyCallback(any(), callbackCaptor.capture())
+        return callbackCaptor.allValues
+    }
+
+    private inline fun <reified T> getTelephonyCallbackForType(): T {
+        val cbs = getTelephonyCallbacks().filterIsInstance<T>()
+        assertThat(cbs.size).isEqualTo(1)
+        return cbs[0]
+    }
+
+    /** Convenience constructor for SignalStrength */
+    private fun signalStrength(gsmLevel: Int, cdmaLevel: Int, isGsm: Boolean): SignalStrength {
+        val signalStrength = mock<SignalStrength>()
+        whenever(signalStrength.isGsm).thenReturn(isGsm)
+        whenever(signalStrength.level).thenReturn(gsmLevel)
+        val cdmaStrength =
+            mock<CellSignalStrengthCdma>().also { whenever(it.level).thenReturn(cdmaLevel) }
+        whenever(signalStrength.getCellSignalStrengths(CellSignalStrengthCdma::class.java))
+            .thenReturn(listOf(cdmaStrength))
+
+        return signalStrength
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+        private const val SUB_1_ID = 1
+        private val SUB_1 =
+            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
+
+        private const val SUB_2_ID = 2
+        private val SUB_2 =
+            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt
new file mode 100644
index 0000000..91c233a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt
@@ -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.systemui.statusbar.pipeline.mobile.data.repository
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class UserSetupRepositoryTest : SysuiTestCase() {
+    private lateinit var underTest: UserSetupRepository
+    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+    private val scope = CoroutineScope(IMMEDIATE)
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            UserSetupRepositoryImpl(
+                deviceProvisionedController,
+                IMMEDIATE,
+                scope,
+            )
+    }
+
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
+
+    @Test
+    fun testUserSetup_defaultFalse() =
+        runBlocking(IMMEDIATE) {
+            var latest: Boolean? = null
+
+            val job = underTest.isUserSetupFlow.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun testUserSetup_updatesOnChange() =
+        runBlocking(IMMEDIATE) {
+            var latest: Boolean? = null
+
+            val job = underTest.isUserSetupFlow.onEach { latest = it }.launchIn(this)
+
+            whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+            val callback = getDeviceProvisionedListener()
+            callback.onUserSetupChanged()
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    private fun getDeviceProvisionedListener(): DeviceProvisionedListener {
+        val captor = argumentCaptor<DeviceProvisionedListener>()
+        verify(deviceProvisionedController).addCallback(captor.capture())
+        return captor.value!!
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
new file mode 100644
index 0000000..8ec68f3
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
@@ -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.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.telephony.CellSignalStrength
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.TelephonyIcons
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeMobileIconInteractor : MobileIconInteractor {
+    private val _iconGroup = MutableStateFlow<SignalIcon.MobileIconGroup>(TelephonyIcons.UNKNOWN)
+    override val iconGroup = _iconGroup
+
+    private val _isEmergencyOnly = MutableStateFlow<Boolean>(false)
+    override val isEmergencyOnly = _isEmergencyOnly
+
+    private val _level = MutableStateFlow<Int>(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+    override val level = _level
+
+    private val _numberOfLevels = MutableStateFlow<Int>(4)
+    override val numberOfLevels = _numberOfLevels
+
+    private val _cutOut = MutableStateFlow<Boolean>(false)
+    override val cutOut = _cutOut
+
+    fun setIconGroup(group: SignalIcon.MobileIconGroup) {
+        _iconGroup.value = group
+    }
+
+    fun setIsEmergencyOnly(emergency: Boolean) {
+        _isEmergencyOnly.value = emergency
+    }
+
+    fun setLevel(level: Int) {
+        _level.value = level
+    }
+
+    fun setNumberOfLevels(num: Int) {
+        _numberOfLevels.value = num
+    }
+
+    fun setCutOut(cutOut: Boolean) {
+        _cutOut.value = cutOut
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.kt
new file mode 100644
index 0000000..2f07d9c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorTest.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.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.telephony.CellSignalStrength
+import android.telephony.SubscriptionInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.model.MobileSubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileSubscriptionRepository
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+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
+
+@SmallTest
+class MobileIconInteractorTest : SysuiTestCase() {
+    private lateinit var underTest: MobileIconInteractor
+    private val mobileSubscriptionRepository = FakeMobileSubscriptionRepository()
+    private val sub1Flow = mobileSubscriptionRepository.getFlowForSubId(SUB_1_ID)
+
+    @Before
+    fun setUp() {
+        underTest = MobileIconInteractorImpl(sub1Flow)
+    }
+
+    @Test
+    fun gsm_level_default_unknown() =
+        runBlocking(IMMEDIATE) {
+            mobileSubscriptionRepository.setMobileSubscriptionModel(
+                MobileSubscriptionModel(isGsm = true),
+                SUB_1_ID
+            )
+
+            var latest: Int? = null
+            val job = underTest.level.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+
+            job.cancel()
+        }
+
+    @Test
+    fun gsm_usesGsmLevel() =
+        runBlocking(IMMEDIATE) {
+            mobileSubscriptionRepository.setMobileSubscriptionModel(
+                MobileSubscriptionModel(
+                    isGsm = true,
+                    primaryLevel = GSM_LEVEL,
+                    cdmaLevel = CDMA_LEVEL
+                ),
+                SUB_1_ID
+            )
+
+            var latest: Int? = null
+            val job = underTest.level.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(GSM_LEVEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun cdma_level_default_unknown() =
+        runBlocking(IMMEDIATE) {
+            mobileSubscriptionRepository.setMobileSubscriptionModel(
+                MobileSubscriptionModel(isGsm = false),
+                SUB_1_ID
+            )
+
+            var latest: Int? = null
+            val job = underTest.level.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+            job.cancel()
+        }
+
+    @Test
+    fun cdma_usesCdmaLevel() =
+        runBlocking(IMMEDIATE) {
+            mobileSubscriptionRepository.setMobileSubscriptionModel(
+                MobileSubscriptionModel(
+                    isGsm = false,
+                    primaryLevel = GSM_LEVEL,
+                    cdmaLevel = CDMA_LEVEL
+                ),
+                SUB_1_ID
+            )
+
+            var latest: Int? = null
+            val job = underTest.level.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(CDMA_LEVEL)
+
+            job.cancel()
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+
+        private const val GSM_LEVEL = 1
+        private const val CDMA_LEVEL = 2
+
+        private const val SUB_1_ID = 1
+        private val SUB_1 =
+            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
+
+        private const val SUB_2_ID = 2
+        private val SUB_2 =
+            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
new file mode 100644
index 0000000..89ad9cb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.mobile.domain.interactor
+
+import android.telephony.SubscriptionInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileSubscriptionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
+import com.android.systemui.util.CarrierConfigTracker
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+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.After
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MobileIconsInteractorTest : SysuiTestCase() {
+    private lateinit var underTest: MobileIconsInteractor
+    private val userSetupRepository = FakeUserSetupRepository()
+    private val subscriptionsRepository = FakeMobileSubscriptionRepository()
+
+    @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            MobileIconsInteractor(
+                subscriptionsRepository,
+                carrierConfigTracker,
+                userSetupRepository,
+            )
+    }
+
+    @After fun tearDown() {}
+
+    @Test
+    fun filteredSubscriptions_default() =
+        runBlocking(IMMEDIATE) {
+            var latest: List<SubscriptionInfo>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(listOf<SubscriptionInfo>())
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
+        runBlocking(IMMEDIATE) {
+            subscriptionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+
+            var latest: List<SubscriptionInfo>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_3() =
+        runBlocking(IMMEDIATE) {
+            subscriptionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
+            subscriptionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(false)
+
+            var latest: List<SubscriptionInfo>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            // Filtered subscriptions should show the active one when the config is false
+            assertThat(latest).isEqualTo(listOf(SUB_3_OPP))
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_bothOpportunistic_configFalse_showsActive_4() =
+        runBlocking(IMMEDIATE) {
+            subscriptionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
+            subscriptionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(false)
+
+            var latest: List<SubscriptionInfo>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            // Filtered subscriptions should show the active one when the config is false
+            assertThat(latest).isEqualTo(listOf(SUB_4_OPP))
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_active_1() =
+        runBlocking(IMMEDIATE) {
+            subscriptionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
+            subscriptionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(true)
+
+            var latest: List<SubscriptionInfo>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            // Filtered subscriptions should show the primary (non-opportunistic) if the config is
+            // true
+            assertThat(latest).isEqualTo(listOf(SUB_1))
+
+            job.cancel()
+        }
+
+    @Test
+    fun filteredSubscriptions_oneOpportunistic_configTrue_showsPrimary_nonActive_1() =
+        runBlocking(IMMEDIATE) {
+            subscriptionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP))
+            subscriptionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(true)
+
+            var latest: List<SubscriptionInfo>? = null
+            val job = underTest.filteredSubscriptions.onEach { latest = it }.launchIn(this)
+
+            // Filtered subscriptions should show the primary (non-opportunistic) if the config is
+            // true
+            assertThat(latest).isEqualTo(listOf(SUB_1))
+
+            job.cancel()
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+
+        private const val SUB_1_ID = 1
+        private val SUB_1 =
+            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_1_ID) }
+
+        private const val SUB_2_ID = 2
+        private val SUB_2 =
+            mock<SubscriptionInfo>().also { whenever(it.subscriptionId).thenReturn(SUB_2_ID) }
+
+        private const val SUB_3_ID = 3
+        private val SUB_3_OPP =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_3_ID)
+                whenever(it.isOpportunistic).thenReturn(true)
+            }
+
+        private const val SUB_4_ID = 4
+        private val SUB_4_OPP =
+            mock<SubscriptionInfo>().also {
+                whenever(it.subscriptionId).thenReturn(SUB_4_ID)
+                whenever(it.isOpportunistic).thenReturn(true)
+            }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
new file mode 100644
index 0000000..b374abb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.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.statusbar.pipeline.mobile.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.settingslib.graph.SignalDrawable
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconInteractor
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+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.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class MobileIconViewModelTest : SysuiTestCase() {
+    private lateinit var underTest: MobileIconViewModel
+    private val interactor = FakeMobileIconInteractor()
+    @Mock private lateinit var logger: ConnectivityPipelineLogger
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        interactor.apply {
+            setLevel(1)
+            setCutOut(false)
+            setIconGroup(TelephonyIcons.THREE_G)
+            setIsEmergencyOnly(false)
+            setNumberOfLevels(4)
+        }
+        underTest = MobileIconViewModel(SUB_1_ID, interactor, logger)
+    }
+
+    @Test
+    fun iconId_correctLevel_notCutout() =
+        runBlocking(IMMEDIATE) {
+            var latest: Int? = null
+            val job = underTest.iconId.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(SignalDrawable.getState(1, 4, false))
+
+            job.cancel()
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+        private const val SUB_1_ID = 1
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
index 36be1be..0e75c74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
@@ -23,9 +23,16 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
 import com.google.common.truth.Truth.assertThat
 import java.io.PrintWriter
 import java.io.StringWriter
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.mockito.Mockito
 import org.mockito.Mockito.mock
@@ -64,12 +71,70 @@
         assertThat(actualString).contains(expectedNetId)
     }
 
-    private val NET_1_ID = 100
-    private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
-        Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
+    @Test
+    fun logOutputChange_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
+        val flow: Flow<Int?> = flowOf(1, null, 3)
+
+        val job = flow
+            .logOutputChange(logger, "testInts")
+            .launchIn(this)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains("1")
+        assertThat(actualString).contains("null")
+        assertThat(actualString).contains("3")
+
+        job.cancel()
     }
-    private val NET_1_CAPS = NetworkCapabilities.Builder()
-        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-        .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
-        .build()
+
+    @Test
+    fun logInputChange_unit_printsInputName() = runBlocking(IMMEDIATE) {
+        val flow: Flow<Unit> = flowOf(Unit, Unit)
+
+        val job = flow
+            .logInputChange(logger, "testInputs")
+            .launchIn(this)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains("testInputs")
+
+        job.cancel()
+    }
+
+    @Test
+    fun logInputChange_any_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
+        val flow: Flow<Any?> = flowOf(null, 2, "threeString")
+
+        val job = flow
+            .logInputChange(logger, "testInputs")
+            .launchIn(this)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains("null")
+        assertThat(actualString).contains("2")
+        assertThat(actualString).contains("threeString")
+
+        job.cancel()
+    }
+
+    companion object {
+        private const val NET_1_ID = 100
+        private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
+            Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
+        }
+        private val NET_1_CAPS = NetworkCapabilities.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+            .build()
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index 6b8d4aa..f751afc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -16,20 +16,27 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.data.repository
 
-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.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
-import kotlinx.coroutines.flow.Flow
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
 
 /** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
 class FakeWifiRepository : WifiRepository {
+    private val _isWifiEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    override val isWifiEnabled: StateFlow<Boolean> = _isWifiEnabled
+
     private val _wifiNetwork: MutableStateFlow<WifiNetworkModel> =
         MutableStateFlow(WifiNetworkModel.Inactive)
-    override val wifiNetwork: Flow<WifiNetworkModel> = _wifiNetwork
+    override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
 
     private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
-    override val wifiActivity: Flow<WifiActivityModel> = _wifiActivity
+    override val wifiActivity: StateFlow<WifiActivityModel> = _wifiActivity
+
+    fun setIsWifiEnabled(enabled: Boolean) {
+        _isWifiEnabled.value = enabled
+    }
 
     fun setWifiNetwork(wifiNetworkModel: WifiNetworkModel) {
         _wifiNetwork.value = wifiNetworkModel
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 d070ba0..0ba0bd6 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
@@ -28,15 +28,17 @@
 import android.net.wifi.WifiManager.TrafficStateCallback
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-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.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.Executor
@@ -44,23 +46,28 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.runBlocking
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class WifiRepositoryImplTest : SysuiTestCase() {
 
     private lateinit var underTest: WifiRepositoryImpl
 
+    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
     @Mock private lateinit var logger: ConnectivityPipelineLogger
     @Mock private lateinit var connectivityManager: ConnectivityManager
     @Mock private lateinit var wifiManager: WifiManager
@@ -70,16 +77,17 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        whenever(
+            broadcastDispatcher.broadcastFlow(
+                any(),
+                nullable(),
+                anyInt(),
+                nullable(),
+            )
+        ).thenReturn(flowOf(Unit))
         executor = FakeExecutor(FakeSystemClock())
         scope = CoroutineScope(IMMEDIATE)
-
-        underTest = WifiRepositoryImpl(
-            connectivityManager,
-            logger,
-            executor,
-            scope,
-            wifiManager,
-        )
+        underTest = createRepo()
     }
 
     @After
@@ -88,6 +96,132 @@
     }
 
     @Test
+    fun isWifiEnabled_nullWifiManager_getsFalse() = runBlocking(IMMEDIATE) {
+        underTest = createRepo(wifiManagerToUse = null)
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+    }
+
+    @Test
+    fun isWifiEnabled_initiallyGetsWifiManagerValue() = runBlocking(IMMEDIATE) {
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+
+        underTest = createRepo()
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+    }
+
+    @Test
+    fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() = runBlocking(IMMEDIATE) {
+        // We need to call launch on the flows so that they start updating
+        val networkJob = underTest.wifiNetwork.launchIn(this)
+        val enabledJob = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        getNetworkCallback().onCapabilitiesChanged(
+            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+        )
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        getNetworkCallback().onCapabilitiesChanged(
+            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+        )
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        networkJob.cancel()
+        enabledJob.cancel()
+    }
+
+    @Test
+    fun isWifiEnabled_networkLost_valueUpdated() = runBlocking(IMMEDIATE) {
+        // We need to call launch on the flows so that they start updating
+        val networkJob = underTest.wifiNetwork.launchIn(this)
+        val enabledJob = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        getNetworkCallback().onLost(NETWORK)
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        getNetworkCallback().onLost(NETWORK)
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        networkJob.cancel()
+        enabledJob.cancel()
+    }
+
+    @Test
+    fun isWifiEnabled_intentsReceived_valueUpdated() = runBlocking(IMMEDIATE) {
+        val intentFlow = MutableSharedFlow<Unit>()
+        whenever(
+            broadcastDispatcher.broadcastFlow(
+                any(),
+                nullable(),
+                anyInt(),
+                nullable(),
+            )
+        ).thenReturn(intentFlow)
+        underTest = createRepo()
+
+        val job = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        intentFlow.emit(Unit)
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        intentFlow.emit(Unit)
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        job.cancel()
+    }
+
+    @Test
+    fun isWifiEnabled_bothIntentAndNetworkUpdates_valueAlwaysUpdated() = runBlocking(IMMEDIATE) {
+        val intentFlow = MutableSharedFlow<Unit>()
+        whenever(
+            broadcastDispatcher.broadcastFlow(
+                any(),
+                nullable(),
+                anyInt(),
+                nullable(),
+            )
+        ).thenReturn(intentFlow)
+        underTest = createRepo()
+
+        val networkJob = underTest.wifiNetwork.launchIn(this)
+        val enabledJob = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        intentFlow.emit(Unit)
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        getNetworkCallback().onLost(NETWORK)
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        getNetworkCallback().onCapabilitiesChanged(
+            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+        )
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        intentFlow.emit(Unit)
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        networkJob.cancel()
+        enabledJob.cancel()
+    }
+
+    @Test
     fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
         var latest: WifiNetworkModel? = null
         val job = underTest
@@ -509,13 +643,7 @@
 
     @Test
     fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
-        underTest = WifiRepositoryImpl(
-            connectivityManager,
-            logger,
-            executor,
-            scope,
-            wifiManager = null,
-        )
+        underTest = createRepo(wifiManagerToUse = null)
 
         var latest: WifiActivityModel? = null
         val job = underTest
@@ -594,6 +722,17 @@
         job.cancel()
     }
 
+    private fun createRepo(wifiManagerToUse: WifiManager? = wifiManager): WifiRepositoryImpl {
+        return WifiRepositoryImpl(
+            broadcastDispatcher,
+            connectivityManager,
+            logger,
+            executor,
+            scope,
+            wifiManagerToUse,
+        )
+    }
+
     private fun getTrafficStateCallback(): TrafficStateCallback {
         val callbackCaptor = argumentCaptor<TrafficStateCallback>()
         verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
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 e896749..39b886a 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
@@ -16,13 +16,14 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
 
+import android.net.wifi.WifiManager
 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
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,172 +51,129 @@
     }
 
     @Test
-    fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
+    fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) {
         wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
 
-        var latest: Boolean? = null
+        var latest: String? = "default"
         val job = underTest
-            .hasActivityIn
+            .ssid
             .onEach { latest = it }
             .launchIn(this)
 
-        assertThat(latest).isFalse()
+        assertThat(latest).isNull()
 
         job.cancel()
     }
 
     @Test
-    fun hasActivityIn_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
+    fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
         wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
 
-        var latest: Boolean? = null
+        var latest: String? = "default"
         val job = underTest
-            .hasActivityIn
+            .ssid
             .onEach { latest = it }
             .launchIn(this)
 
-        assertThat(latest).isFalse()
+        assertThat(latest).isNull()
 
         job.cancel()
     }
 
     @Test
-    fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+    fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            isPasspointAccessPoint = true,
+            passpointProviderFriendlyName = "friendly",
+        ))
 
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("friendly")
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            isOnlineSignUpForPasspointAccessPoint = true,
+            passpointProviderFriendlyName = "friendly",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("friendly")
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            ssid = WifiManager.UNKNOWN_SSID,
+        ))
+
+        var latest: String? = "default"
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            ssid = "MyAwesomeWifiNetwork",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("MyAwesomeWifiNetwork")
+
+        job.cancel()
+    }
+
+    @Test
+    fun isEnabled_matchesRepoIsEnabled() = runBlocking(IMMEDIATE) {
         var latest: Boolean? = null
         val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
+            .isEnabled
+            .onEach { latest = it }
+            .launchIn(this)
 
-        // Conduct a series of changes and verify we catch each of them in succession
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
+        wifiRepository.setIsWifiEnabled(true)
         yield()
         assertThat(latest).isTrue()
 
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
-        )
+        wifiRepository.setIsWifiEnabled(false)
         yield()
         assertThat(latest).isFalse()
 
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
+        wifiRepository.setIsWifiEnabled(true)
         yield()
         assertThat(latest).isTrue()
 
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
-        yield()
-        assertThat(latest).isTrue()
-
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
-        )
-        yield()
-        assertThat(latest).isFalse()
-
         job.cancel()
     }
 
@@ -242,6 +200,32 @@
     }
 
     @Test
+    fun activity_matchesRepoWifiActivity() = runBlocking(IMMEDIATE) {
+        var latest: WifiActivityModel? = null
+        val job = underTest
+            .activity
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity1 = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity1)
+        yield()
+        assertThat(latest).isEqualTo(activity1)
+
+        val activity2 = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity2)
+        yield()
+        assertThat(latest).isEqualTo(activity2)
+
+        val activity3 = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity3)
+        yield()
+        assertThat(latest).isEqualTo(activity3)
+
+        job.cancel()
+    }
+
+    @Test
     fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
         connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
 
@@ -270,10 +254,6 @@
 
         job.cancel()
     }
-
-    companion object {
-        val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
-    }
 }
 
 private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 3c200a5..4efb135 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -16,38 +16,225 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.ui.view
 
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import android.testing.ViewUtils
+import android.view.View
 import androidx.test.filters.SmallTest
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.lifecycle.InstantTaskExecutorRule
-import com.android.systemui.util.Assert
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+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
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
 import org.junit.Before
 import org.junit.Rule
 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)
-@RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
 class ModernStatusBarWifiViewTest : SysuiTestCase() {
 
+    private lateinit var testableLooper: TestableLooper
+
+    @Mock
+    private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
+    @Mock
+    private lateinit var logger: ConnectivityPipelineLogger
+    @Mock
+    private lateinit var connectivityConstants: ConnectivityConstants
+    @Mock
+    private lateinit var wifiConstants: WifiConstants
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
+    private lateinit var interactor: WifiInteractor
+    private lateinit var viewModel: WifiViewModel
+    private lateinit var scope: CoroutineScope
+
     @JvmField @Rule
     val instantTaskExecutor = InstantTaskExecutorRule()
 
     @Before
     fun setUp() {
-        Assert.setTestThread(Thread.currentThread())
+        MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
+
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        wifiRepository.setIsWifiEnabled(true)
+        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        scope = CoroutineScope(Dispatchers.Unconfined)
+        viewModel = WifiViewModel(
+            connectivityConstants,
+            context,
+            logger,
+            interactor,
+            scope,
+            statusBarPipelineFlags,
+            wifiConstants,
+        )
     }
 
     @Test
     fun constructAndBind_hasCorrectSlot() {
         val view = ModernStatusBarWifiView.constructAndBind(
-            context, "slotName", mock()
+            context, "slotName", viewModel, StatusBarLocation.HOME
         )
 
         assertThat(view.slot).isEqualTo("slotName")
     }
+
+    @Test
+    fun getVisibleState_icon_returnsIcon() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_ICON, /* animate= */ false)
+
+        assertThat(view.visibleState).isEqualTo(STATE_ICON)
+    }
+
+    @Test
+    fun getVisibleState_dot_returnsDot() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_DOT, /* animate= */ false)
+
+        assertThat(view.visibleState).isEqualTo(STATE_DOT)
+    }
+
+    @Test
+    fun getVisibleState_hidden_returnsHidden() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_HIDDEN, /* animate= */ false)
+
+        assertThat(view.visibleState).isEqualTo(STATE_HIDDEN)
+    }
+
+    // Note: The following tests are more like integration tests, since they stand up a full
+    // [WifiViewModel] and test the interactions between the view, view-binder, and view-model.
+
+    @Test
+    fun setVisibleState_icon_iconShownDotHidden() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_ICON, /* animate= */ false)
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.getIconGroupView().visibility).isEqualTo(View.VISIBLE)
+        assertThat(view.getDotView().visibility).isEqualTo(View.GONE)
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun setVisibleState_dot_iconHiddenDotShown() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_DOT, /* animate= */ false)
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.getIconGroupView().visibility).isEqualTo(View.GONE)
+        assertThat(view.getDotView().visibility).isEqualTo(View.VISIBLE)
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun setVisibleState_hidden_iconAndDotHidden() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_HIDDEN, /* animate= */ false)
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.getIconGroupView().visibility).isEqualTo(View.GONE)
+        assertThat(view.getDotView().visibility).isEqualTo(View.GONE)
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun isIconVisible_notEnabled_outputsFalse() {
+        wifiRepository.setIsWifiEnabled(false)
+        wifiRepository.setWifiNetwork(
+            WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
+        )
+
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.isIconVisible).isFalse()
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun isIconVisible_enabled_outputsTrue() {
+        wifiRepository.setIsWifiEnabled(true)
+        wifiRepository.setWifiNetwork(
+            WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
+        )
+
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.isIconVisible).isTrue()
+
+        ViewUtils.detachView(view)
+    }
+
+    private fun View.getIconGroupView(): View {
+        return this.requireViewById(R.id.wifi_group)
+    }
+
+    private fun View.getDotView(): View {
+        return this.requireViewById(R.id.status_bar_dot)
+    }
 }
+
+private const val SLOT_NAME = "TestSlotName"
+private const val NETWORK_ID = 200
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
new file mode 100644
index 0000000..929e529
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.wifi.ui.viewmodel
+
+import android.content.Context
+import androidx.annotation.DrawableRes
+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.statusbar.connectivity.WifiIcons
+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.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+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.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.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(Parameterized::class)
+internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase) :
+    SysuiTestCase() {
+
+    private lateinit var underTest: WifiViewModel
+
+    @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
+    @Mock private lateinit var logger: ConnectivityPipelineLogger
+    @Mock private lateinit var connectivityConstants: ConnectivityConstants
+    @Mock private lateinit var wifiConstants: WifiConstants
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
+    private lateinit var interactor: WifiInteractor
+    private lateinit var scope: CoroutineScope
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        wifiRepository.setIsWifiEnabled(true)
+        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        scope = CoroutineScope(IMMEDIATE)
+    }
+
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
+
+    @Test
+    fun wifiIcon() =
+        runBlocking(IMMEDIATE) {
+            wifiRepository.setIsWifiEnabled(testCase.enabled)
+            connectivityRepository.setForceHiddenIcons(
+                if (testCase.forceHidden) {
+                    setOf(ConnectivitySlot.WIFI)
+                } else {
+                    setOf()
+                }
+            )
+            whenever(wifiConstants.alwaysShowIconIfEnabled)
+                .thenReturn(testCase.alwaysShowIconWhenEnabled)
+            whenever(connectivityConstants.hasDataCapabilities)
+                .thenReturn(testCase.hasDataCapabilities)
+            underTest =
+                WifiViewModel(
+                    connectivityConstants,
+                    context,
+                    logger,
+                    interactor,
+                    scope,
+                    statusBarPipelineFlags,
+                    wifiConstants,
+                )
+
+            val iconFlow = underTest.home.wifiIcon
+            val job = iconFlow.launchIn(this)
+
+            // WHEN we set a certain network
+            wifiRepository.setWifiNetwork(testCase.network)
+            yield()
+
+            // THEN we get the expected icon
+            assertThat(iconFlow.value?.res).isEqualTo(testCase.expected?.iconResource)
+            val expectedContentDescription =
+                if (testCase.expected == null) {
+                    null
+                } else {
+                    testCase.expected.contentDescription.invoke(context)
+                }
+            assertThat(iconFlow.value?.contentDescription?.getAsString())
+                .isEqualTo(expectedContentDescription)
+
+            job.cancel()
+        }
+
+    private fun ContentDescription.getAsString(): String? {
+        return when (this) {
+            is ContentDescription.Loaded -> this.description
+            is ContentDescription.Resource -> context.getString(this.res)
+        }
+    }
+
+    internal data class Expected(
+        /** The resource that should be used for the icon. */
+        @DrawableRes val iconResource: Int,
+
+        /** A function that, given a context, calculates the correct content description string. */
+        val contentDescription: (Context) -> String,
+    )
+
+    // Note: We use default values for the boolean parameters to reflect a "typical configuration"
+    //   for wifi. This allows each TestCase to only define the parameter values that are critical
+    //   for the test function.
+    internal data class TestCase(
+        val enabled: Boolean = true,
+        val forceHidden: Boolean = false,
+        val alwaysShowIconWhenEnabled: Boolean = false,
+        val hasDataCapabilities: Boolean = true,
+        val network: WifiNetworkModel,
+
+        /** The expected output. Null if we expect the output to be null. */
+        val expected: Expected?
+    )
+
+    companion object {
+        @Parameters(name = "{0}")
+        @JvmStatic
+        fun data(): Collection<TestCase> =
+            listOf(
+                // Enabled = false => no networks shown
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.CarrierMerged,
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Inactive,
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 1),
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 3),
+                    expected = null,
+                ),
+
+                // forceHidden = true => no networks shown
+                TestCase(
+                    forceHidden = true,
+                    network = WifiNetworkModel.CarrierMerged,
+                    expected = null,
+                ),
+                TestCase(
+                    forceHidden = true,
+                    network = WifiNetworkModel.Inactive,
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 2),
+                    expected = null,
+                ),
+                TestCase(
+                    forceHidden = true,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1),
+                    expected = null,
+                ),
+
+                // alwaysShowIconWhenEnabled = true => all Inactive and Active networks shown
+                TestCase(
+                    alwaysShowIconWhenEnabled = true,
+                    network = WifiNetworkModel.Inactive,
+                    expected =
+                        Expected(
+                            iconResource = WifiIcons.WIFI_NO_NETWORK,
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_NO_CONNECTION)}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    alwaysShowIconWhenEnabled = true,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 4),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_NO_INTERNET_ICONS[4],
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_CONNECTION_STRENGTH[4])}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    alwaysShowIconWhenEnabled = true,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_FULL_ICONS[2],
+                            contentDescription = { context ->
+                                context.getString(WIFI_CONNECTION_STRENGTH[2])
+                            }
+                        ),
+                ),
+
+                // hasDataCapabilities = false => all Inactive and Active networks shown
+                TestCase(
+                    hasDataCapabilities = false,
+                    network = WifiNetworkModel.Inactive,
+                    expected =
+                        Expected(
+                            iconResource = WifiIcons.WIFI_NO_NETWORK,
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_NO_CONNECTION)}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    hasDataCapabilities = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 2),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_NO_INTERNET_ICONS[2],
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_CONNECTION_STRENGTH[2])}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    hasDataCapabilities = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 0),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_FULL_ICONS[0],
+                            contentDescription = { context ->
+                                context.getString(WIFI_CONNECTION_STRENGTH[0])
+                            }
+                        ),
+                ),
+
+                // network = CarrierMerged => not shown
+                TestCase(
+                    network = WifiNetworkModel.CarrierMerged,
+                    expected = null,
+                ),
+
+                // network = Inactive => not shown
+                TestCase(
+                    network = WifiNetworkModel.Inactive,
+                    expected = null,
+                ),
+
+                // network = Active & validated = false => not shown
+                TestCase(
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
+                    expected = null,
+                ),
+
+                // network = Active & validated = true => shown
+                TestCase(
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 4),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_FULL_ICONS[4],
+                            contentDescription = { context ->
+                                context.getString(WIFI_CONNECTION_STRENGTH[4])
+                            }
+                        ),
+                ),
+
+                // network has null level => not shown
+                TestCase(
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = null),
+                    expected = null,
+                ),
+            )
+    }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
+private const val NETWORK_ID = 789
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 43103a0..3169eef 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,37 +17,34 @@
 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.ConnectivityConstants
 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.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 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.`when` as whenever
 import org.mockito.MockitoAnnotations
 
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class WifiViewModelTest : SysuiTestCase() {
@@ -56,236 +53,426 @@
 
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var logger: ConnectivityPipelineLogger
-    @Mock private lateinit var constants: WifiConstants
+    @Mock private lateinit var connectivityConstants: ConnectivityConstants
+    @Mock private lateinit var wifiConstants: WifiConstants
     private lateinit var connectivityRepository: FakeConnectivityRepository
     private lateinit var wifiRepository: FakeWifiRepository
     private lateinit var interactor: WifiInteractor
+    private lateinit var scope: CoroutineScope
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
+        wifiRepository.setIsWifiEnabled(true)
         interactor = WifiInteractor(connectivityRepository, wifiRepository)
-
-        underTest = WifiViewModel(
-            statusBarPipelineFlags,
-            constants,
-            context,
-            logger,
-            interactor
-        )
+        scope = CoroutineScope(IMMEDIATE)
+        createAndSetViewModel()
     }
 
-    @Test
-    fun wifiIcon_forceHidden_outputsNull() = runBlocking(IMMEDIATE) {
-        connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
 
-        var latest: Icon? = null
-        val job = underTest
+    // Note on testing: [WifiViewModel] exposes 3 different instances of
+    // [LocationBasedWifiViewModel]. In practice, these 3 different instances will get the exact
+    // same data for icon, activity, etc. flows. So, most of these tests will test just one of the
+    // instances. There are also some tests that verify all 3 instances received the same data.
+
+    @Test
+    fun wifiIcon_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) {
+        var latestHome: Icon? = null
+        val jobHome = underTest
+            .home
             .wifiIcon
-            .onEach { latest = it }
+            .onEach { latestHome = it }
             .launchIn(this)
 
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_notForceHidden_outputsVisible() = runBlocking(IMMEDIATE) {
-        connectivityRepository.setForceHiddenIcons(setOf())
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
-
-        var latest: Icon? = null
-        val job = underTest
+        var latestKeyguard: Icon? = null
+        val jobKeyguard = underTest
+            .keyguard
             .wifiIcon
-            .onEach { latest = it }
+            .onEach { latestKeyguard = 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
+        var latestQs: Icon? = null
+        val jobQs = underTest
+            .qs
             .wifiIcon
-            .onEach { latest = it }
+            .onEach { latestQs = 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
-
         wifiRepository.setWifiNetwork(
-                WifiNetworkModel.Active(
-                        NETWORK_ID,
-                        isValidated = true,
-                        level = level
-                )
-        )
-
-        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_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 wifiIcon_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
-        val level = 4
-
-        wifiRepository.setWifiNetwork(
-                WifiNetworkModel.Active(
-                        NETWORK_ID,
-                        isValidated = false,
-                        level = level
-                )
-        )
-
-        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_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()
-    }
-
-    @Test
-    fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
-        whenever(constants.shouldShowActivityConfig).thenReturn(false)
-        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
-
-        var latest: Boolean? = null
-        val job = underTest
-                .isActivityInVisible
-                .onEach { latest = it }
-                .launchIn(this)
-
-        // Verify that on launch, we receive a false.
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
-        whenever(constants.shouldShowActivityConfig).thenReturn(false)
-        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
-
-        var latest: Boolean? = null
-        val job = underTest
-                .isActivityInVisible
-                .onEach { latest = it }
-                .launchIn(this)
-
-        // Update the repo to have activityIn
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+            WifiNetworkModel.Active(
+                NETWORK_ID,
+                isValidated = true,
+                level = 1
+            )
         )
         yield()
 
-        // Verify that we didn't update to activityIn=true (because our config is false)
-        assertThat(latest).isFalse()
+        assertThat(latestHome).isInstanceOf(Icon.Resource::class.java)
+        assertThat(latestHome).isEqualTo(latestKeyguard)
+        assertThat(latestKeyguard).isEqualTo(latestQs)
 
-        job.cancel()
+        jobHome.cancel()
+        jobKeyguard.cancel()
+        jobQs.cancel()
     }
 
     @Test
-    fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
-        whenever(constants.shouldShowActivityConfig).thenReturn(true)
+    fun activity_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(false)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var activityIn: Boolean? = null
+        val activityInJob = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { activityIn = it }
+            .launchIn(this)
+
+        var activityOut: Boolean? = null
+        val activityOutJob = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { activityOut = it }
+            .launchIn(this)
+
+        var activityContainer: Boolean? = null
+        val activityContainerJob = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { activityContainer = it }
+            .launchIn(this)
+
+        // Verify that on launch, we receive false.
+        assertThat(activityIn).isFalse()
+        assertThat(activityOut).isFalse()
+        assertThat(activityContainer).isFalse()
+
+        activityInJob.cancel()
+        activityOutJob.cancel()
+        activityContainerJob.cancel()
+    }
+
+    @Test
+    fun activity_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(false)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var activityIn: Boolean? = null
+        val activityInJob = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { activityIn = it }
+            .launchIn(this)
+
+        var activityOut: Boolean? = null
+        val activityOutJob = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { activityOut = it }
+            .launchIn(this)
+
+        var activityContainer: Boolean? = null
+        val activityContainerJob = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { activityContainer = it }
+            .launchIn(this)
+
+        // WHEN we update the repo to have activity
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        // THEN we didn't update to the new activity (because our config is false)
+        assertThat(activityIn).isFalse()
+        assertThat(activityOut).isFalse()
+        assertThat(activityContainer).isFalse()
+
+        activityInJob.cancel()
+        activityOutJob.cancel()
+        activityContainerJob.cancel()
+    }
+
+    @Test
+    fun activity_nullSsid_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null))
+
+        var activityIn: Boolean? = null
+        val activityInJob = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { activityIn = it }
+            .launchIn(this)
+
+        var activityOut: Boolean? = null
+        val activityOutJob = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { activityOut = it }
+            .launchIn(this)
+
+        var activityContainer: Boolean? = null
+        val activityContainerJob = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { activityContainer = it }
+            .launchIn(this)
+
+        // WHEN we update the repo to have activity
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        // THEN we still output false because our network's SSID is null
+        assertThat(activityIn).isFalse()
+        assertThat(activityOut).isFalse()
+        assertThat(activityContainer).isFalse()
+
+        activityInJob.cancel()
+        activityOutJob.cancel()
+        activityContainerJob.cancel()
+    }
+
+    @Test
+    fun activity_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latestHome: Boolean? = null
+        val jobHome = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { latestHome = it }
+            .launchIn(this)
+
+        var latestKeyguard: Boolean? = null
+        val jobKeyguard = underTest
+            .keyguard
+            .isActivityInViewVisible
+            .onEach { latestKeyguard = it }
+            .launchIn(this)
+
+        var latestQs: Boolean? = null
+        val jobQs = underTest
+            .qs
+            .isActivityInViewVisible
+            .onEach { latestQs = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latestHome).isTrue()
+        assertThat(latestKeyguard).isTrue()
+        assertThat(latestQs).isTrue()
+
+        jobHome.cancel()
+        jobKeyguard.cancel()
+        jobQs.cancel()
+    }
+
+    @Test
+    fun activityIn_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
         wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
 
         var latest: Boolean? = null
         val job = underTest
-                .isActivityInVisible
-                .onEach { latest = it }
-                .launchIn(this)
+            .home
+            .isActivityInViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
 
-        // Update the repo to have activityIn
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
         yield()
 
-        // Verify that we updated to activityIn=true
         assertThat(latest).isTrue()
 
         job.cancel()
     }
 
-    private fun ContentDescription.getAsString(): String? {
-        return when (this) {
-            is ContentDescription.Loaded -> this.description
-            is ContentDescription.Resource -> context.getString(this.res)
-        }
+    @Test
+    fun activityIn_hasActivityInFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityOut_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityOut_hasActivityOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_inAndOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_inAndOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
+    private fun createAndSetViewModel() {
+        // [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow
+        // creations rely on certain config values that we mock out in individual tests. This method
+        // allows tests to create the view model only after those configs are correctly set up.
+        underTest = WifiViewModel(
+            connectivityConstants,
+            context,
+            logger,
+            interactor,
+            scope,
+            statusBarPipelineFlags,
+            wifiConstants,
+        )
     }
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index c47ea9c..6ace404 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -275,10 +275,9 @@
         EditText editText = view.findViewById(R.id.remote_input_text);
         editText.setText(TEST_REPLY);
         ClipDescription description = new ClipDescription("", new String[] {"image/png"});
-        // We need to use an (arbitrary) real resource here so that an actual image gets attached.
+        // We need to use an (arbitrary) real resource here so that an actual image gets attached
         ClipData clip = new ClipData(description, new ClipData.Item(
-                Uri.parse("android.resource://com.android.systemui/"
-                        + R.drawable.default_thumbnail)));
+                Uri.parse("android.resource://android/" + android.R.drawable.btn_default)));
         ContentInfo payload =
                 new ContentInfo.Builder(clip, SOURCE_CLIPBOARD).build();
         view.setAttachment(payload);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.kt
new file mode 100644
index 0000000..773a0d8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/telephony/data/repository/TelephonyRepositoryImplTest.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.telephony.data.repository
+
+import android.telephony.TelephonyCallback
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.telephony.TelephonyListenerManager
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+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.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class TelephonyRepositoryImplTest : SysuiTestCase() {
+
+    @Mock private lateinit var manager: TelephonyListenerManager
+
+    private lateinit var underTest: TelephonyRepositoryImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        underTest =
+            TelephonyRepositoryImpl(
+                manager = manager,
+            )
+    }
+
+    @Test
+    fun callState() =
+        runBlocking(IMMEDIATE) {
+            var callState: Int? = null
+            val job = underTest.callState.onEach { callState = it }.launchIn(this)
+            val listenerCaptor = kotlinArgumentCaptor<TelephonyCallback.CallStateListener>()
+            verify(manager).addCallStateListener(listenerCaptor.capture())
+            val listener = listenerCaptor.value
+
+            listener.onCallStateChanged(0)
+            assertThat(callState).isEqualTo(0)
+
+            listener.onCallStateChanged(1)
+            assertThat(callState).isEqualTo(1)
+
+            listener.onCallStateChanged(2)
+            assertThat(callState).isEqualTo(2)
+
+            job.cancel()
+
+            verify(manager).removeCallStateListener(listener)
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index 921b7ef..c4abedd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -17,7 +17,9 @@
 package com.android.systemui.temporarydisplay
 
 import android.content.Context
+import android.graphics.Rect
 import android.os.PowerManager
+import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManager
 import android.view.accessibility.AccessibilityManager
@@ -61,6 +63,8 @@
     @Mock
     private lateinit var powerManager: PowerManager
 
+    private var shouldIgnoreViewRemoval: Boolean = false
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
@@ -205,6 +209,26 @@
         verify(windowManager, never()).removeView(any())
     }
 
+    @Test
+    fun removeView_shouldIgnoreRemovalFalse_viewRemoved() {
+        shouldIgnoreViewRemoval = false
+        underTest.displayView(getState())
+
+        underTest.removeView("reason")
+
+        verify(windowManager).removeView(any())
+    }
+
+    @Test
+    fun removeView_shouldIgnoreRemovalTrue_viewNotRemoved() {
+        shouldIgnoreViewRemoval = true
+        underTest.displayView(getState())
+
+        underTest.removeView("reason")
+
+        verify(windowManager, never()).removeView(any())
+    }
+
     private fun getState(name: String = "name") = ViewInfo(name)
 
     private fun getConfigurationListener(): ConfigurationListener {
@@ -236,10 +260,20 @@
         var mostRecentViewInfo: ViewInfo? = null
 
         override val windowLayoutParams = commonWindowLayoutParams
+
+        override fun start() {}
+
         override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) {
-            super.updateView(newInfo, currentView)
             mostRecentViewInfo = newInfo
         }
+
+        override fun shouldIgnoreViewRemoval(info: ViewInfo, removalReason: String): Boolean {
+            return shouldIgnoreViewRemoval
+        }
+
+        override fun getTouchableRegion(view: View, outRect: Rect) {
+            outRect.setEmpty()
+        }
     }
 
     inner class ViewInfo(val name: String) : TemporaryViewInfo {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
new file mode 100644
index 0000000..7586fe4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TouchableRegionViewControllerTest.kt
@@ -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.temporarydisplay
+
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewTreeObserver
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class TouchableRegionViewControllerTest : SysuiTestCase() {
+
+    @Mock private lateinit var view: View
+    @Mock private lateinit var viewTreeObserver: ViewTreeObserver
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(view.viewTreeObserver).thenReturn(viewTreeObserver)
+    }
+
+    @Test
+    fun viewAttached_listenerAdded() {
+        val controller = TouchableRegionViewController(view) { _, _ -> }
+
+        controller.onViewAttached()
+
+        verify(viewTreeObserver).addOnComputeInternalInsetsListener(any())
+    }
+
+    @Test
+    fun viewDetached_listenerRemoved() {
+        val controller = TouchableRegionViewController(view) { _, _ -> }
+
+        controller.onViewDetached()
+
+        verify(viewTreeObserver).removeOnComputeInternalInsetsListener(any())
+    }
+
+    @Test
+    fun listener_usesPassedInFunction() {
+        val controller =
+            TouchableRegionViewController(view) { _, outRect -> outRect.set(1, 2, 3, 4) }
+
+        controller.onViewAttached()
+
+        val captor =
+            ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener::class.java)
+        verify(viewTreeObserver).addOnComputeInternalInsetsListener(captor.capture())
+        val listener = captor.value!!
+
+        val inoutInfo = ViewTreeObserver.InternalInsetsInfo()
+        listener.onComputeInternalInsets(inoutInfo)
+
+        assertThat(inoutInfo.touchableRegion.bounds).isEqualTo(Rect(1, 2, 3, 4))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 50259b5..2a93fff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -885,4 +885,31 @@
         assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
                 .isEqualTo(new OverlayIdentifier("ff00ff00"));
     }
+
+    // Regression test for b/234603929, where a reboot would generate a wallpaper colors changed
+    // event for the already-set colors that would then set the theme incorrectly on screen sleep.
+    @Test
+    public void onWallpaperColorsSetToSame_keepsTheme() {
+        // Set initial colors and verify.
+        WallpaperColors startingColors = new WallpaperColors(Color.valueOf(Color.RED),
+                Color.valueOf(Color.BLUE), null);
+        WallpaperColors sameColors = new WallpaperColors(Color.valueOf(Color.RED),
+                Color.valueOf(Color.BLUE), null);
+        mColorsListener.getValue().onColorsChanged(startingColors, WallpaperManager.FLAG_SYSTEM,
+                USER_SYSTEM);
+        verify(mThemeOverlayApplier)
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+        clearInvocations(mThemeOverlayApplier);
+
+        // Set to the same colors.
+        mColorsListener.getValue().onColorsChanged(sameColors, WallpaperManager.FLAG_SYSTEM,
+                USER_SYSTEM);
+        verify(mThemeOverlayApplier, never())
+                .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+
+        // Verify that no change resulted.
+        mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep();
+        verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
+                any());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt
new file mode 100644
index 0000000..d951f36
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplRefactoredTest.kt
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.UserHandle
+import android.os.UserManager
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.systemui.user.data.model.UserSwitcherSettingsModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+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.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserRepositoryImplRefactoredTest : UserRepositoryImplTest() {
+
+    @Before
+    fun setUp() {
+        super.setUp(isRefactored = true)
+    }
+
+    @Test
+    fun userSwitcherSettings() = runSelfCancelingTest {
+        setUpGlobalSettings(
+            isSimpleUserSwitcher = true,
+            isAddUsersFromLockscreen = true,
+            isUserSwitcherEnabled = true,
+        )
+        underTest = create(this)
+
+        var value: UserSwitcherSettingsModel? = null
+        underTest.userSwitcherSettings.onEach { value = it }.launchIn(this)
+
+        assertUserSwitcherSettings(
+            model = value,
+            expectedSimpleUserSwitcher = true,
+            expectedAddUsersFromLockscreen = true,
+            expectedUserSwitcherEnabled = true,
+        )
+
+        setUpGlobalSettings(
+            isSimpleUserSwitcher = false,
+            isAddUsersFromLockscreen = true,
+            isUserSwitcherEnabled = true,
+        )
+        assertUserSwitcherSettings(
+            model = value,
+            expectedSimpleUserSwitcher = false,
+            expectedAddUsersFromLockscreen = true,
+            expectedUserSwitcherEnabled = true,
+        )
+    }
+
+    @Test
+    fun refreshUsers() = runSelfCancelingTest {
+        underTest = create(this)
+        val initialExpectedValue =
+            setUpUsers(
+                count = 3,
+                selectedIndex = 0,
+            )
+        var userInfos: List<UserInfo>? = null
+        var selectedUserInfo: UserInfo? = null
+        underTest.userInfos.onEach { userInfos = it }.launchIn(this)
+        underTest.selectedUserInfo.onEach { selectedUserInfo = it }.launchIn(this)
+
+        underTest.refreshUsers()
+        assertThat(userInfos).isEqualTo(initialExpectedValue)
+        assertThat(selectedUserInfo).isEqualTo(initialExpectedValue[0])
+        assertThat(underTest.lastSelectedNonGuestUserId).isEqualTo(selectedUserInfo?.id)
+
+        val secondExpectedValue =
+            setUpUsers(
+                count = 4,
+                selectedIndex = 1,
+            )
+        underTest.refreshUsers()
+        assertThat(userInfos).isEqualTo(secondExpectedValue)
+        assertThat(selectedUserInfo).isEqualTo(secondExpectedValue[1])
+        assertThat(underTest.lastSelectedNonGuestUserId).isEqualTo(selectedUserInfo?.id)
+
+        val selectedNonGuestUserId = selectedUserInfo?.id
+        val thirdExpectedValue =
+            setUpUsers(
+                count = 2,
+                hasGuest = true,
+                selectedIndex = 1,
+            )
+        underTest.refreshUsers()
+        assertThat(userInfos).isEqualTo(thirdExpectedValue)
+        assertThat(selectedUserInfo).isEqualTo(thirdExpectedValue[1])
+        assertThat(selectedUserInfo?.isGuest).isTrue()
+        assertThat(underTest.lastSelectedNonGuestUserId).isEqualTo(selectedNonGuestUserId)
+    }
+
+    @Test
+    fun `refreshUsers - sorts by creation time`() = runSelfCancelingTest {
+        underTest = create(this)
+        val unsortedUsers =
+            setUpUsers(
+                count = 3,
+                selectedIndex = 0,
+            )
+        unsortedUsers[0].creationTime = 900
+        unsortedUsers[1].creationTime = 700
+        unsortedUsers[2].creationTime = 999
+        val expectedUsers = listOf(unsortedUsers[1], unsortedUsers[0], unsortedUsers[2])
+        var userInfos: List<UserInfo>? = null
+        var selectedUserInfo: UserInfo? = null
+        underTest.userInfos.onEach { userInfos = it }.launchIn(this)
+        underTest.selectedUserInfo.onEach { selectedUserInfo = it }.launchIn(this)
+
+        underTest.refreshUsers()
+        assertThat(userInfos).isEqualTo(expectedUsers)
+    }
+
+    private fun setUpUsers(
+        count: Int,
+        hasGuest: Boolean = false,
+        selectedIndex: Int = 0,
+    ): List<UserInfo> {
+        val userInfos =
+            (0 until count).map { index ->
+                createUserInfo(
+                    index,
+                    isGuest = hasGuest && index == count - 1,
+                )
+            }
+        whenever(manager.aliveUsers).thenReturn(userInfos)
+        tracker.set(userInfos, selectedIndex)
+        return userInfos
+    }
+
+    private fun createUserInfo(
+        id: Int,
+        isGuest: Boolean,
+    ): UserInfo {
+        val flags = 0
+        return UserInfo(
+            id,
+            "user_$id",
+            /* iconPath= */ "",
+            flags,
+            if (isGuest) UserManager.USER_TYPE_FULL_GUEST else UserInfo.getDefaultUserType(flags),
+        )
+    }
+
+    private fun setUpGlobalSettings(
+        isSimpleUserSwitcher: Boolean = false,
+        isAddUsersFromLockscreen: Boolean = false,
+        isUserSwitcherEnabled: Boolean = true,
+    ) {
+        context.orCreateTestableResources.addOverride(
+            com.android.internal.R.bool.config_expandLockScreenUserSwitcher,
+            true,
+        )
+        globalSettings.putIntForUser(
+            UserRepositoryImpl.SETTING_SIMPLE_USER_SWITCHER,
+            if (isSimpleUserSwitcher) 1 else 0,
+            UserHandle.USER_SYSTEM,
+        )
+        globalSettings.putIntForUser(
+            Settings.Global.ADD_USERS_WHEN_LOCKED,
+            if (isAddUsersFromLockscreen) 1 else 0,
+            UserHandle.USER_SYSTEM,
+        )
+        globalSettings.putIntForUser(
+            Settings.Global.USER_SWITCHER_ENABLED,
+            if (isUserSwitcherEnabled) 1 else 0,
+            UserHandle.USER_SYSTEM,
+        )
+    }
+
+    private fun assertUserSwitcherSettings(
+        model: UserSwitcherSettingsModel?,
+        expectedSimpleUserSwitcher: Boolean,
+        expectedAddUsersFromLockscreen: Boolean,
+        expectedUserSwitcherEnabled: Boolean,
+    ) {
+        checkNotNull(model)
+        assertThat(model.isSimpleUserSwitcher).isEqualTo(expectedSimpleUserSwitcher)
+        assertThat(model.isAddUsersFromLockscreen).isEqualTo(expectedAddUsersFromLockscreen)
+        assertThat(model.isUserSwitcherEnabled).isEqualTo(expectedUserSwitcherEnabled)
+    }
+
+    /**
+     * Executes the given block of execution within the scope of a dedicated [CoroutineScope] which
+     * is then automatically canceled and cleaned-up.
+     */
+    private fun runSelfCancelingTest(
+        block: suspend CoroutineScope.() -> Unit,
+    ) =
+        runBlocking(Dispatchers.Main.immediate) {
+            val scope = CoroutineScope(coroutineContext + Job())
+            block(scope)
+            scope.cancel()
+        }
+}
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
index 6fec343..dcea83a 100644
--- 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
@@ -17,201 +17,54 @@
 
 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.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.settings.FakeUserTracker
 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 com.android.systemui.util.settings.FakeSettings
+import kotlinx.coroutines.CoroutineScope
 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 kotlinx.coroutines.test.TestCoroutineScope
 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() {
+abstract class UserRepositoryImplTest : SysuiTestCase() {
 
-    @Mock private lateinit var manager: UserManager
-    @Mock private lateinit var controller: UserSwitcherController
-    @Captor
-    private lateinit var userSwitchCallbackCaptor:
-        ArgumentCaptor<UserSwitcherController.UserSwitchCallback>
+    @Mock protected lateinit var manager: UserManager
+    @Mock protected lateinit var controller: UserSwitcherController
 
-    private lateinit var underTest: UserRepositoryImpl
+    protected lateinit var underTest: UserRepositoryImpl
 
-    @Before
-    fun setUp() {
+    protected lateinit var globalSettings: FakeSettings
+    protected lateinit var tracker: FakeUserTracker
+    protected lateinit var featureFlags: FakeFeatureFlags
+
+    protected fun setUp(isRefactored: Boolean) {
         MockitoAnnotations.initMocks(this)
-        whenever(controller.isAddUsersFromLockScreenEnabled).thenReturn(MutableStateFlow(false))
-        whenever(controller.isGuestUserAutoCreated).thenReturn(false)
-        whenever(controller.isGuestUserResetting).thenReturn(false)
 
-        underTest =
-            UserRepositoryImpl(
-                appContext = context,
-                manager = manager,
-                controller = controller,
-            )
+        globalSettings = FakeSettings()
+        tracker = FakeUserTracker()
+        featureFlags = FakeFeatureFlags()
+        featureFlags.set(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER, !isRefactored)
     }
 
-    @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,
+    protected fun create(scope: CoroutineScope = TestCoroutineScope()): UserRepositoryImpl {
+        return UserRepositoryImpl(
+            appContext = context,
+            manager = manager,
+            controller = controller,
+            applicationScope = scope,
+            mainDispatcher = IMMEDIATE,
+            backgroundDispatcher = IMMEDIATE,
+            globalSettings = globalSettings,
+            tracker = tracker,
+            featureFlags = featureFlags,
         )
     }
 
     companion object {
-        private val IMMEDIATE = Dispatchers.Main.immediate
+        @JvmStatic protected val IMMEDIATE = Dispatchers.Main.immediate
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplUnrefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplUnrefactoredTest.kt
new file mode 100644
index 0000000..d4b41c1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplUnrefactoredTest.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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 androidx.test.filters.SmallTest
+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.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserRepositoryImplUnrefactoredTest : UserRepositoryImplTest() {
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+
+    @Captor
+    private lateinit var userSwitchCallbackCaptor:
+        ArgumentCaptor<UserSwitcherController.UserSwitchCallback>
+
+    @Before
+    fun setUp() {
+        super.setUp(isRefactored = false)
+
+        whenever(controller.isAddUsersFromLockScreenEnabled).thenReturn(MutableStateFlow(false))
+        whenever(controller.isGuestUserAutoCreated).thenReturn(false)
+        whenever(controller.isGuestUserResetting).thenReturn(false)
+
+        underTest = create()
+    }
+
+    @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 `actions - 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,
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
new file mode 100644
index 0000000..120bf79
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/GuestUserInteractorTest.kt
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.app.admin.DevicePolicyManager
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import android.os.UserManager
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.model.ShowDialogRequestModel
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class GuestUserInteractorTest : SysuiTestCase() {
+
+    @Mock private lateinit var manager: UserManager
+    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock private lateinit var devicePolicyManager: DevicePolicyManager
+    @Mock private lateinit var uiEventLogger: UiEventLogger
+    @Mock private lateinit var showDialog: (ShowDialogRequestModel) -> Unit
+    @Mock private lateinit var dismissDialog: () -> Unit
+    @Mock private lateinit var selectUser: (Int) -> Unit
+    @Mock private lateinit var switchUser: (Int) -> Unit
+
+    private lateinit var underTest: GuestUserInteractor
+
+    private lateinit var scope: TestCoroutineScope
+    private lateinit var repository: FakeUserRepository
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(manager.createGuest(any())).thenReturn(GUEST_USER_INFO)
+
+        scope = TestCoroutineScope()
+        repository = FakeUserRepository()
+        repository.setUserInfos(ALL_USERS)
+
+        underTest =
+            GuestUserInteractor(
+                applicationContext = context,
+                applicationScope = scope,
+                mainDispatcher = IMMEDIATE,
+                backgroundDispatcher = IMMEDIATE,
+                manager = manager,
+                repository = repository,
+                deviceProvisionedController = deviceProvisionedController,
+                devicePolicyManager = devicePolicyManager,
+                refreshUsersScheduler =
+                    RefreshUsersScheduler(
+                        applicationScope = scope,
+                        mainDispatcher = IMMEDIATE,
+                        repository = repository,
+                    ),
+                uiEventLogger = uiEventLogger,
+            )
+    }
+
+    @Test
+    fun `onDeviceBootCompleted - allowed to add - create guest`() =
+        runBlocking(IMMEDIATE) {
+            setAllowedToAdd()
+
+            underTest.onDeviceBootCompleted()
+
+            verify(manager).createGuest(any())
+            verify(deviceProvisionedController, never()).addCallback(any())
+        }
+
+    @Test
+    fun `onDeviceBootCompleted - await provisioning - and create guest`() =
+        runBlocking(IMMEDIATE) {
+            setAllowedToAdd(isAllowed = false)
+            underTest.onDeviceBootCompleted()
+            val captor =
+                kotlinArgumentCaptor<DeviceProvisionedController.DeviceProvisionedListener>()
+            verify(deviceProvisionedController).addCallback(captor.capture())
+
+            setAllowedToAdd(isAllowed = true)
+            captor.value.onDeviceProvisionedChanged()
+
+            verify(manager).createGuest(any())
+            verify(deviceProvisionedController).removeCallback(captor.value)
+        }
+
+    @Test
+    fun createAndSwitchTo() =
+        runBlocking(IMMEDIATE) {
+            underTest.createAndSwitchTo(
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                selectUser = selectUser,
+            )
+
+            verify(showDialog).invoke(ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true))
+            verify(manager).createGuest(any())
+            verify(dismissDialog).invoke()
+            verify(selectUser).invoke(GUEST_USER_INFO.id)
+        }
+
+    @Test
+    fun `createAndSwitchTo - fails to create - does not switch to`() =
+        runBlocking(IMMEDIATE) {
+            whenever(manager.createGuest(any())).thenReturn(null)
+
+            underTest.createAndSwitchTo(
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                selectUser = selectUser,
+            )
+
+            verify(showDialog).invoke(ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true))
+            verify(manager).createGuest(any())
+            verify(dismissDialog).invoke()
+            verify(selectUser, never()).invoke(anyInt())
+        }
+
+    @Test
+    fun `exit - returns to target user`() =
+        runBlocking(IMMEDIATE) {
+            repository.setSelectedUserInfo(GUEST_USER_INFO)
+
+            val targetUserId = NON_GUEST_USER_INFO.id
+            underTest.exit(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = targetUserId,
+                forceRemoveGuestOnExit = false,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verify(manager, never()).markGuestForDeletion(anyInt())
+            verify(manager, never()).removeUser(anyInt())
+            verify(switchUser).invoke(targetUserId)
+        }
+
+    @Test
+    fun `exit - returns to last non-guest`() =
+        runBlocking(IMMEDIATE) {
+            val expectedUserId = NON_GUEST_USER_INFO.id
+            whenever(manager.getUserInfo(expectedUserId)).thenReturn(NON_GUEST_USER_INFO)
+            repository.lastSelectedNonGuestUserId = expectedUserId
+            repository.setSelectedUserInfo(GUEST_USER_INFO)
+
+            underTest.exit(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = UserHandle.USER_NULL,
+                forceRemoveGuestOnExit = false,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verify(manager, never()).markGuestForDeletion(anyInt())
+            verify(manager, never()).removeUser(anyInt())
+            verify(switchUser).invoke(expectedUserId)
+        }
+
+    @Test
+    fun `exit - last non-guest was removed - returns to system`() =
+        runBlocking(IMMEDIATE) {
+            val removedUserId = 310
+            repository.lastSelectedNonGuestUserId = removedUserId
+            repository.setSelectedUserInfo(GUEST_USER_INFO)
+
+            underTest.exit(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = UserHandle.USER_NULL,
+                forceRemoveGuestOnExit = false,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verify(manager, never()).markGuestForDeletion(anyInt())
+            verify(manager, never()).removeUser(anyInt())
+            verify(switchUser).invoke(UserHandle.USER_SYSTEM)
+        }
+
+    @Test
+    fun `exit - guest was ephemeral - it is removed`() =
+        runBlocking(IMMEDIATE) {
+            whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
+            repository.setUserInfos(listOf(NON_GUEST_USER_INFO, EPHEMERAL_GUEST_USER_INFO))
+            repository.setSelectedUserInfo(EPHEMERAL_GUEST_USER_INFO)
+            val targetUserId = NON_GUEST_USER_INFO.id
+
+            underTest.exit(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = targetUserId,
+                forceRemoveGuestOnExit = false,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verify(manager).markGuestForDeletion(EPHEMERAL_GUEST_USER_INFO.id)
+            verify(manager).removeUser(EPHEMERAL_GUEST_USER_INFO.id)
+            verify(switchUser).invoke(targetUserId)
+        }
+
+    @Test
+    fun `exit - force remove guest - it is removed`() =
+        runBlocking(IMMEDIATE) {
+            whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
+            repository.setSelectedUserInfo(GUEST_USER_INFO)
+            val targetUserId = NON_GUEST_USER_INFO.id
+
+            underTest.exit(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = targetUserId,
+                forceRemoveGuestOnExit = true,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verify(manager).markGuestForDeletion(GUEST_USER_INFO.id)
+            verify(manager).removeUser(GUEST_USER_INFO.id)
+            verify(switchUser).invoke(targetUserId)
+        }
+
+    @Test
+    fun `exit - selected different from guest user - do nothing`() =
+        runBlocking(IMMEDIATE) {
+            repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
+
+            underTest.exit(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = 123,
+                forceRemoveGuestOnExit = false,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verifyDidNotExit()
+        }
+
+    @Test
+    fun `exit - selected is actually not a guest user - do nothing`() =
+        runBlocking(IMMEDIATE) {
+            repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
+
+            underTest.exit(
+                guestUserId = NON_GUEST_USER_INFO.id,
+                targetUserId = 123,
+                forceRemoveGuestOnExit = false,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verifyDidNotExit()
+        }
+
+    @Test
+    fun `remove - returns to target user`() =
+        runBlocking(IMMEDIATE) {
+            whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
+            repository.setSelectedUserInfo(GUEST_USER_INFO)
+
+            val targetUserId = NON_GUEST_USER_INFO.id
+            underTest.remove(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = targetUserId,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verify(manager).markGuestForDeletion(GUEST_USER_INFO.id)
+            verify(manager).removeUser(GUEST_USER_INFO.id)
+            verify(switchUser).invoke(targetUserId)
+        }
+
+    @Test
+    fun `remove - selected different from guest user - do nothing`() =
+        runBlocking(IMMEDIATE) {
+            whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
+            repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
+
+            underTest.remove(
+                guestUserId = GUEST_USER_INFO.id,
+                targetUserId = 123,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verifyDidNotRemove()
+        }
+
+    @Test
+    fun `remove - selected is actually not a guest user - do nothing`() =
+        runBlocking(IMMEDIATE) {
+            whenever(manager.markGuestForDeletion(anyInt())).thenReturn(true)
+            repository.setSelectedUserInfo(NON_GUEST_USER_INFO)
+
+            underTest.remove(
+                guestUserId = NON_GUEST_USER_INFO.id,
+                targetUserId = 123,
+                showDialog = showDialog,
+                dismissDialog = dismissDialog,
+                switchUser = switchUser,
+            )
+
+            verifyDidNotRemove()
+        }
+
+    private fun setAllowedToAdd(isAllowed: Boolean = true) {
+        whenever(deviceProvisionedController.isDeviceProvisioned).thenReturn(isAllowed)
+        whenever(devicePolicyManager.isDeviceManaged).thenReturn(!isAllowed)
+    }
+
+    private fun verifyDidNotExit() {
+        verifyDidNotRemove()
+        verify(manager, never()).getUserInfo(anyInt())
+        verify(uiEventLogger, never()).log(any())
+    }
+
+    private fun verifyDidNotRemove() {
+        verify(manager, never()).markGuestForDeletion(anyInt())
+        verify(showDialog, never()).invoke(any())
+        verify(dismissDialog, never()).invoke()
+        verify(switchUser, never()).invoke(anyInt())
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+        private val NON_GUEST_USER_INFO =
+            UserInfo(
+                /* id= */ 818,
+                /* name= */ "non_guest",
+                /* flags= */ 0,
+            )
+        private val GUEST_USER_INFO =
+            UserInfo(
+                /* id= */ 669,
+                /* name= */ "guest",
+                /* iconPath= */ "",
+                /* flags= */ 0,
+                UserManager.USER_TYPE_FULL_GUEST,
+            )
+        private val EPHEMERAL_GUEST_USER_INFO =
+            UserInfo(
+                /* id= */ 669,
+                /* name= */ "guest",
+                /* iconPath= */ "",
+                /* flags= */ UserInfo.FLAG_EPHEMERAL,
+                UserManager.USER_TYPE_FULL_GUEST,
+            )
+        private val ALL_USERS =
+            listOf(
+                NON_GUEST_USER_INFO,
+                GUEST_USER_INFO,
+            )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
new file mode 100644
index 0000000..593ce1f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/RefreshUsersSchedulerTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.user.data.repository.FakeUserRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+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.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class RefreshUsersSchedulerTest : SysuiTestCase() {
+
+    private lateinit var underTest: RefreshUsersScheduler
+
+    private lateinit var repository: FakeUserRepository
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+
+        repository = FakeUserRepository()
+    }
+
+    @Test
+    fun `pause - prevents the next refresh from happening`() =
+        runBlocking(IMMEDIATE) {
+            underTest =
+                RefreshUsersScheduler(
+                    applicationScope = this,
+                    mainDispatcher = IMMEDIATE,
+                    repository = repository,
+                )
+            underTest.pause()
+
+            underTest.refreshIfNotPaused()
+            assertThat(repository.refreshUsersCallCount).isEqualTo(0)
+        }
+
+    @Test
+    fun `unpauseAndRefresh - forces the refresh even when paused`() =
+        runBlocking(IMMEDIATE) {
+            underTest =
+                RefreshUsersScheduler(
+                    applicationScope = this,
+                    mainDispatcher = IMMEDIATE,
+                    repository = repository,
+                )
+            underTest.pause()
+
+            underTest.unpauseAndRefresh()
+
+            assertThat(repository.refreshUsersCallCount).isEqualTo(1)
+        }
+
+    @Test
+    fun `refreshIfNotPaused - refreshes when not paused`() =
+        runBlocking(IMMEDIATE) {
+            underTest =
+                RefreshUsersScheduler(
+                    applicationScope = this,
+                    mainDispatcher = IMMEDIATE,
+                    repository = repository,
+                )
+            underTest.refreshIfNotPaused()
+
+            assertThat(repository.refreshUsersCallCount).isEqualTo(1)
+        }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
new file mode 100644
index 0000000..37c378c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorRefactoredTest.kt
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF 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.content.pm.UserInfo
+import android.graphics.Bitmap
+import android.graphics.drawable.Drawable
+import android.os.UserHandle
+import android.os.UserManager
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.internal.R.drawable.ic_account_circle
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.user.data.model.UserSwitcherSettingsModel
+import com.android.systemui.user.data.source.UserRecord
+import com.android.systemui.user.domain.model.ShowDialogRequestModel
+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.eq
+import com.android.systemui.util.mockito.kotlinArgumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+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.ArgumentMatchers.anyBoolean
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(JUnit4::class)
+class UserInteractorRefactoredTest : UserInteractorTest() {
+
+    override fun isRefactored(): Boolean {
+        return true
+    }
+
+    @Before
+    override fun setUp() {
+        super.setUp()
+
+        overrideResource(R.drawable.ic_account_circle, GUEST_ICON)
+        overrideResource(R.dimen.max_avatar_size, 10)
+        overrideResource(
+            com.android.internal.R.string.config_supervisedUserCreationPackage,
+            SUPERVISED_USER_CREATION_APP_PACKAGE,
+        )
+        whenever(manager.getUserIcon(anyInt())).thenReturn(ICON)
+        whenever(manager.canAddMoreUsers(any())).thenReturn(true)
+    }
+
+    @Test
+    fun `onRecordSelected - user`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+            underTest.onRecordSelected(UserRecord(info = userInfos[1]), dialogShower)
+
+            verify(dialogShower).dismiss()
+            verify(activityManager).switchUser(userInfos[1].id)
+            Unit
+        }
+
+    @Test
+    fun `onRecordSelected - switch to guest user`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = true)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+            underTest.onRecordSelected(UserRecord(info = userInfos.last()))
+
+            verify(activityManager).switchUser(userInfos.last().id)
+            Unit
+        }
+
+    @Test
+    fun `onRecordSelected - enter guest mode`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            val guestUserInfo = createUserInfo(id = 1337, name = "guest", isGuest = true)
+            whenever(manager.createGuest(any())).thenReturn(guestUserInfo)
+
+            underTest.onRecordSelected(UserRecord(isGuest = true), dialogShower)
+
+            verify(dialogShower).dismiss()
+            verify(manager).createGuest(any())
+            Unit
+        }
+
+    @Test
+    fun `onRecordSelected - action`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = true)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+            underTest.onRecordSelected(UserRecord(isAddSupervisedUser = true), dialogShower)
+
+            verify(dialogShower, never()).dismiss()
+            verify(activityStarter).startActivity(any(), anyBoolean())
+        }
+
+    @Test
+    fun `users - switcher enabled`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = true)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+            var value: List<UserModel>? = null
+            val job = underTest.users.onEach { value = it }.launchIn(this)
+            assertUsers(models = value, count = 3, includeGuest = true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun `users - switches to second user`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+            var value: List<UserModel>? = null
+            val job = underTest.users.onEach { value = it }.launchIn(this)
+            userRepository.setSelectedUserInfo(userInfos[1])
+
+            assertUsers(models = value, count = 2, selectedIndex = 1)
+            job.cancel()
+        }
+
+    @Test
+    fun `users - switcher not enabled`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = false))
+
+            var value: List<UserModel>? = null
+            val job = underTest.users.onEach { value = it }.launchIn(this)
+            assertUsers(models = value, count = 1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun selectedUser() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+
+            var value: UserModel? = null
+            val job = underTest.selectedUser.onEach { value = it }.launchIn(this)
+            assertUser(value, id = 0, isSelected = true)
+
+            userRepository.setSelectedUserInfo(userInfos[1])
+            assertUser(value, id = 1, isSelected = true)
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - device unlocked`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            keyguardRepository.setKeyguardShowing(false)
+            var value: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { value = it }.launchIn(this)
+
+            assertThat(value)
+                .isEqualTo(
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.ADD_USER,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                    )
+                )
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - device unlocked user not primary - empty list`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[1])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            keyguardRepository.setKeyguardShowing(false)
+            var value: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { value = it }.launchIn(this)
+
+            assertThat(value).isEqualTo(emptyList<UserActionModel>())
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - device unlocked user is guest - empty list`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = true)
+            assertThat(userInfos[1].isGuest).isTrue()
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[1])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            keyguardRepository.setKeyguardShowing(false)
+            var value: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { value = it }.launchIn(this)
+
+            assertThat(value).isEqualTo(emptyList<UserActionModel>())
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - device locked add from lockscreen set - full list`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(
+                UserSwitcherSettingsModel(
+                    isUserSwitcherEnabled = true,
+                    isAddUsersFromLockscreen = true,
+                )
+            )
+            keyguardRepository.setKeyguardShowing(false)
+            var value: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { value = it }.launchIn(this)
+
+            assertThat(value)
+                .isEqualTo(
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.ADD_USER,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                    )
+                )
+
+            job.cancel()
+        }
+
+    @Test
+    fun `actions - device locked - only guest action is shown`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            keyguardRepository.setKeyguardShowing(true)
+            var value: List<UserActionModel>? = null
+            val job = underTest.actions.onEach { value = it }.launchIn(this)
+
+            assertThat(value).isEqualTo(listOf(UserActionModel.ENTER_GUEST_MODE))
+
+            job.cancel()
+        }
+
+    @Test
+    fun `executeAction - add user - dialog shown`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            keyguardRepository.setKeyguardShowing(false)
+            var dialogRequest: ShowDialogRequestModel? = null
+            val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
+
+            underTest.executeAction(UserActionModel.ADD_USER)
+            assertThat(dialogRequest)
+                .isEqualTo(
+                    ShowDialogRequestModel.ShowAddUserDialog(
+                        userHandle = userInfos[0].userHandle,
+                        isKeyguardShowing = false,
+                        showEphemeralMessage = false,
+                    )
+                )
+
+            underTest.onDialogShown()
+            assertThat(dialogRequest).isNull()
+
+            job.cancel()
+        }
+
+    @Test
+    fun `executeAction - add supervised user - starts activity`() =
+        runBlocking(IMMEDIATE) {
+            underTest.executeAction(UserActionModel.ADD_SUPERVISED_USER)
+
+            val intentCaptor = kotlinArgumentCaptor<Intent>()
+            verify(activityStarter).startActivity(intentCaptor.capture(), eq(false))
+            assertThat(intentCaptor.value.action)
+                .isEqualTo(UserManager.ACTION_CREATE_SUPERVISED_USER)
+            assertThat(intentCaptor.value.`package`).isEqualTo(SUPERVISED_USER_CREATION_APP_PACKAGE)
+        }
+
+    @Test
+    fun `executeAction - navigate to manage users`() =
+        runBlocking(IMMEDIATE) {
+            underTest.executeAction(UserActionModel.NAVIGATE_TO_USER_MANAGEMENT)
+
+            val intentCaptor = kotlinArgumentCaptor<Intent>()
+            verify(activityStarter).startActivity(intentCaptor.capture(), eq(false))
+            assertThat(intentCaptor.value.action).isEqualTo(Settings.ACTION_USER_SETTINGS)
+        }
+
+    @Test
+    fun `executeAction - guest mode`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            val guestUserInfo = createUserInfo(id = 1337, name = "guest", isGuest = true)
+            whenever(manager.createGuest(any())).thenReturn(guestUserInfo)
+            val dialogRequests = mutableListOf<ShowDialogRequestModel?>()
+            val showDialogsJob =
+                underTest.dialogShowRequests
+                    .onEach {
+                        dialogRequests.add(it)
+                        if (it != null) {
+                            underTest.onDialogShown()
+                        }
+                    }
+                    .launchIn(this)
+            val dismissDialogsJob =
+                underTest.dialogDismissRequests
+                    .onEach {
+                        if (it != null) {
+                            underTest.onDialogDismissed()
+                        }
+                    }
+                    .launchIn(this)
+
+            underTest.executeAction(UserActionModel.ENTER_GUEST_MODE)
+
+            assertThat(dialogRequests)
+                .contains(
+                    ShowDialogRequestModel.ShowUserCreationDialog(isGuest = true),
+                )
+            verify(activityManager).switchUser(guestUserInfo.id)
+
+            showDialogsJob.cancel()
+            dismissDialogsJob.cancel()
+        }
+
+    @Test
+    fun `selectUser - already selected guest re-selected - exit guest dialog`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = true)
+            val guestUserInfo = userInfos[1]
+            assertThat(guestUserInfo.isGuest).isTrue()
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(guestUserInfo)
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            var dialogRequest: ShowDialogRequestModel? = null
+            val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
+
+            underTest.selectUser(
+                newlySelectedUserId = guestUserInfo.id,
+                dialogShower = dialogShower,
+            )
+
+            assertThat(dialogRequest)
+                .isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java)
+            verify(dialogShower, never()).dismiss()
+            job.cancel()
+        }
+
+    @Test
+    fun `selectUser - currently guest non-guest selected - exit guest dialog`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = true)
+            val guestUserInfo = userInfos[1]
+            assertThat(guestUserInfo.isGuest).isTrue()
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(guestUserInfo)
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            var dialogRequest: ShowDialogRequestModel? = null
+            val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
+
+            underTest.selectUser(newlySelectedUserId = userInfos[0].id, dialogShower = dialogShower)
+
+            assertThat(dialogRequest)
+                .isInstanceOf(ShowDialogRequestModel.ShowExitGuestDialog::class.java)
+            verify(dialogShower, never()).dismiss()
+            job.cancel()
+        }
+
+    @Test
+    fun `selectUser - not currently guest - switches users`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            var dialogRequest: ShowDialogRequestModel? = null
+            val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
+
+            underTest.selectUser(newlySelectedUserId = userInfos[1].id, dialogShower = dialogShower)
+
+            assertThat(dialogRequest).isNull()
+            verify(activityManager).switchUser(userInfos[1].id)
+            verify(dialogShower).dismiss()
+            job.cancel()
+        }
+
+    @Test
+    fun `Telephony call state changes - refreshes users`() =
+        runBlocking(IMMEDIATE) {
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            telephonyRepository.setCallState(1)
+
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+        }
+
+    @Test
+    fun `User switched broadcast`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            val callback1: UserInteractor.UserCallback = mock()
+            val callback2: UserInteractor.UserCallback = mock()
+            underTest.addCallback(callback1)
+            underTest.addCallback(callback2)
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            userRepository.setSelectedUserInfo(userInfos[1])
+            fakeBroadcastDispatcher.registeredReceivers.forEach {
+                it.onReceive(
+                    context,
+                    Intent(Intent.ACTION_USER_SWITCHED)
+                        .putExtra(Intent.EXTRA_USER_HANDLE, userInfos[1].id),
+                )
+            }
+
+            verify(callback1).onUserStateChanged()
+            verify(callback2).onUserStateChanged()
+            assertThat(userRepository.secondaryUserId).isEqualTo(userInfos[1].id)
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+        }
+
+    @Test
+    fun `User info changed broadcast`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            fakeBroadcastDispatcher.registeredReceivers.forEach {
+                it.onReceive(
+                    context,
+                    Intent(Intent.ACTION_USER_INFO_CHANGED),
+                )
+            }
+
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+        }
+
+    @Test
+    fun `System user unlocked broadcast - refresh users`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            fakeBroadcastDispatcher.registeredReceivers.forEach {
+                it.onReceive(
+                    context,
+                    Intent(Intent.ACTION_USER_UNLOCKED)
+                        .putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_SYSTEM),
+                )
+            }
+
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount + 1)
+        }
+
+    @Test
+    fun `Non-system user unlocked broadcast - do not refresh users`() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 2, includeGuest = false)
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            val refreshUsersCallCount = userRepository.refreshUsersCallCount
+
+            fakeBroadcastDispatcher.registeredReceivers.forEach {
+                it.onReceive(
+                    context,
+                    Intent(Intent.ACTION_USER_UNLOCKED).putExtra(Intent.EXTRA_USER_HANDLE, 1337),
+                )
+            }
+
+            assertThat(userRepository.refreshUsersCallCount).isEqualTo(refreshUsersCallCount)
+        }
+
+    @Test
+    fun userRecords() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = false)
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            keyguardRepository.setKeyguardShowing(false)
+
+            testCoroutineScope.advanceUntilIdle()
+
+            assertRecords(
+                records = underTest.userRecords.value,
+                userIds = listOf(0, 1, 2),
+                selectedUserIndex = 0,
+                includeGuest = false,
+                expectedActions =
+                    listOf(
+                        UserActionModel.ENTER_GUEST_MODE,
+                        UserActionModel.ADD_USER,
+                        UserActionModel.ADD_SUPERVISED_USER,
+                    ),
+            )
+        }
+
+    @Test
+    fun selectedUserRecord() =
+        runBlocking(IMMEDIATE) {
+            val userInfos = createUserInfos(count = 3, includeGuest = true)
+            userRepository.setSettings(UserSwitcherSettingsModel(isUserSwitcherEnabled = true))
+            userRepository.setUserInfos(userInfos)
+            userRepository.setSelectedUserInfo(userInfos[0])
+            keyguardRepository.setKeyguardShowing(false)
+
+            assertRecordForUser(
+                record = underTest.selectedUserRecord.value,
+                id = 0,
+                hasPicture = true,
+                isCurrent = true,
+                isSwitchToEnabled = true,
+            )
+        }
+
+    private fun assertUsers(
+        models: List<UserModel>?,
+        count: Int,
+        selectedIndex: Int = 0,
+        includeGuest: Boolean = false,
+    ) {
+        checkNotNull(models)
+        assertThat(models.size).isEqualTo(count)
+        models.forEachIndexed { index, model ->
+            assertUser(
+                model = model,
+                id = index,
+                isSelected = index == selectedIndex,
+                isGuest = includeGuest && index == count - 1
+            )
+        }
+    }
+
+    private fun assertUser(
+        model: UserModel?,
+        id: Int,
+        isSelected: Boolean = false,
+        isGuest: Boolean = false,
+    ) {
+        checkNotNull(model)
+        assertThat(model.id).isEqualTo(id)
+        assertThat(model.name).isEqualTo(Text.Loaded(if (isGuest) "guest" else "user_$id"))
+        assertThat(model.isSelected).isEqualTo(isSelected)
+        assertThat(model.isSelectable).isTrue()
+        assertThat(model.isGuest).isEqualTo(isGuest)
+    }
+
+    private fun assertRecords(
+        records: List<UserRecord>,
+        userIds: List<Int>,
+        selectedUserIndex: Int = 0,
+        includeGuest: Boolean = false,
+        expectedActions: List<UserActionModel> = emptyList(),
+    ) {
+        assertThat(records.size >= userIds.size).isTrue()
+        userIds.indices.forEach { userIndex ->
+            val record = records[userIndex]
+            assertThat(record.info).isNotNull()
+            val isGuest = includeGuest && userIndex == userIds.size - 1
+            assertRecordForUser(
+                record = record,
+                id = userIds[userIndex],
+                hasPicture = !isGuest,
+                isCurrent = userIndex == selectedUserIndex,
+                isGuest = isGuest,
+                isSwitchToEnabled = true,
+            )
+        }
+
+        assertThat(records.size - userIds.size).isEqualTo(expectedActions.size)
+        (userIds.size until userIds.size + expectedActions.size).forEach { actionIndex ->
+            val record = records[actionIndex]
+            assertThat(record.info).isNull()
+            assertRecordForAction(
+                record = record,
+                type = expectedActions[actionIndex - userIds.size],
+            )
+        }
+    }
+
+    private fun assertRecordForUser(
+        record: UserRecord?,
+        id: Int? = null,
+        hasPicture: Boolean = false,
+        isCurrent: Boolean = false,
+        isGuest: Boolean = false,
+        isSwitchToEnabled: Boolean = false,
+    ) {
+        checkNotNull(record)
+        assertThat(record.info?.id).isEqualTo(id)
+        assertThat(record.picture != null).isEqualTo(hasPicture)
+        assertThat(record.isCurrent).isEqualTo(isCurrent)
+        assertThat(record.isGuest).isEqualTo(isGuest)
+        assertThat(record.isSwitchToEnabled).isEqualTo(isSwitchToEnabled)
+    }
+
+    private fun assertRecordForAction(
+        record: UserRecord,
+        type: UserActionModel,
+    ) {
+        assertThat(record.isGuest).isEqualTo(type == UserActionModel.ENTER_GUEST_MODE)
+        assertThat(record.isAddUser).isEqualTo(type == UserActionModel.ADD_USER)
+        assertThat(record.isAddSupervisedUser)
+            .isEqualTo(type == UserActionModel.ADD_SUPERVISED_USER)
+    }
+
+    private fun createUserInfos(
+        count: Int,
+        includeGuest: Boolean,
+    ): List<UserInfo> {
+        return (0 until count).map { index ->
+            val isGuest = includeGuest && index == count - 1
+            createUserInfo(
+                id = index,
+                name =
+                    if (isGuest) {
+                        "guest"
+                    } else {
+                        "user_$index"
+                    },
+                isPrimary = !isGuest && index == 0,
+                isGuest = isGuest,
+            )
+        }
+    }
+
+    private fun createUserInfo(
+        id: Int,
+        name: String,
+        isPrimary: Boolean = false,
+        isGuest: Boolean = false,
+    ): UserInfo {
+        return UserInfo(
+            id,
+            name,
+            /* iconPath= */ "",
+            /* flags= */ if (isPrimary) {
+                UserInfo.FLAG_PRIMARY
+            } else {
+                0
+            },
+            if (isGuest) {
+                UserManager.USER_TYPE_FULL_GUEST
+            } else {
+                UserManager.USER_TYPE_FULL_SYSTEM
+            },
+        )
+    }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+        private val ICON = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+        private val GUEST_ICON: Drawable = mock()
+        private const val SUPERVISED_USER_CREATION_APP_PACKAGE = "supervisedUserCreation"
+    }
+}
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
index e914e2e..1680c36c 100644
--- 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
@@ -17,51 +17,63 @@
 
 package com.android.systemui.user.domain.interactor
 
-import androidx.test.filters.SmallTest
+import android.app.ActivityManager
+import android.app.admin.DevicePolicyManager
+import android.os.UserManager
+import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.user.UserSwitchDialogController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
+import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
 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 kotlinx.coroutines.test.TestCoroutineScope
 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() {
+abstract class UserInteractorTest : SysuiTestCase() {
 
-    @Mock private lateinit var controller: UserSwitcherController
-    @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock protected lateinit var controller: UserSwitcherController
+    @Mock protected lateinit var activityStarter: ActivityStarter
+    @Mock protected lateinit var manager: UserManager
+    @Mock protected lateinit var activityManager: ActivityManager
+    @Mock protected lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock protected lateinit var devicePolicyManager: DevicePolicyManager
+    @Mock protected lateinit var uiEventLogger: UiEventLogger
+    @Mock protected lateinit var dialogShower: UserSwitchDialogController.DialogShower
 
-    private lateinit var underTest: UserInteractor
+    protected lateinit var underTest: UserInteractor
 
-    private lateinit var userRepository: FakeUserRepository
-    private lateinit var keyguardRepository: FakeKeyguardRepository
+    protected lateinit var testCoroutineScope: TestCoroutineScope
+    protected lateinit var userRepository: FakeUserRepository
+    protected lateinit var keyguardRepository: FakeKeyguardRepository
+    protected lateinit var telephonyRepository: FakeTelephonyRepository
 
-    @Before
-    fun setUp() {
+    abstract fun isRefactored(): Boolean
+
+    open fun setUp() {
         MockitoAnnotations.initMocks(this)
 
         userRepository = FakeUserRepository()
         keyguardRepository = FakeKeyguardRepository()
+        telephonyRepository = FakeTelephonyRepository()
+        testCoroutineScope = TestCoroutineScope()
+        val refreshUsersScheduler =
+            RefreshUsersScheduler(
+                applicationScope = testCoroutineScope,
+                mainDispatcher = IMMEDIATE,
+                repository = userRepository,
+            )
         underTest =
             UserInteractor(
+                applicationContext = context,
                 repository = userRepository,
                 controller = controller,
                 activityStarter = activityStarter,
@@ -69,142 +81,34 @@
                     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,
+                featureFlags =
+                    FakeFeatureFlags().apply {
+                        set(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER, !isRefactored())
+                    },
+                manager = manager,
+                applicationScope = testCoroutineScope,
+                telephonyInteractor =
+                    TelephonyInteractor(
+                        repository = telephonyRepository,
+                    ),
+                broadcastDispatcher = fakeBroadcastDispatcher,
+                backgroundDispatcher = IMMEDIATE,
+                activityManager = activityManager,
+                refreshUsersScheduler = refreshUsersScheduler,
+                guestUserInteractor =
+                    GuestUserInteractor(
+                        applicationContext = context,
+                        applicationScope = testCoroutineScope,
+                        mainDispatcher = IMMEDIATE,
+                        backgroundDispatcher = IMMEDIATE,
+                        manager = manager,
+                        repository = userRepository,
+                        deviceProvisionedController = deviceProvisionedController,
+                        devicePolicyManager = devicePolicyManager,
+                        refreshUsersScheduler = refreshUsersScheduler,
+                        uiEventLogger = uiEventLogger,
                     )
-                )
-            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 {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorUnrefactoredTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorUnrefactoredTest.kt
new file mode 100644
index 0000000..c3a9705
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorUnrefactoredTest.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user.domain.interactor
+
+import androidx.test.filters.SmallTest
+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.Mockito.anyBoolean
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(JUnit4::class)
+open class UserInteractorUnrefactoredTest : UserInteractorTest() {
+
+    override fun isRefactored(): Boolean {
+        return false
+    }
+
+    @Before
+    override fun setUp() {
+        super.setUp()
+    }
+
+    @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
index ef4500d..0344e3f 100644
--- 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
@@ -17,17 +17,28 @@
 
 package com.android.systemui.user.ui.viewmodel
 
+import android.app.ActivityManager
+import android.app.admin.DevicePolicyManager
 import android.graphics.drawable.Drawable
+import android.os.UserManager
 import androidx.test.filters.SmallTest
+import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Text
+import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.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.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserSwitcherController
+import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
+import com.android.systemui.telephony.domain.interactor.TelephonyInteractor
 import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.GuestUserInteractor
+import com.android.systemui.user.domain.interactor.RefreshUsersScheduler
 import com.android.systemui.user.domain.interactor.UserInteractor
 import com.android.systemui.user.legacyhelper.ui.LegacyUserUiHelper
 import com.android.systemui.user.shared.model.UserActionModel
@@ -38,6 +49,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineScope
 import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
@@ -52,6 +64,11 @@
 
     @Mock private lateinit var controller: UserSwitcherController
     @Mock private lateinit var activityStarter: ActivityStarter
+    @Mock private lateinit var activityManager: ActivityManager
+    @Mock private lateinit var manager: UserManager
+    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
+    @Mock private lateinit var devicePolicyManager: DevicePolicyManager
+    @Mock private lateinit var uiEventLogger: UiEventLogger
 
     private lateinit var underTest: UserSwitcherViewModel
 
@@ -66,22 +83,60 @@
         userRepository = FakeUserRepository()
         keyguardRepository = FakeKeyguardRepository()
         powerRepository = FakePowerRepository()
+        val featureFlags = FakeFeatureFlags()
+        featureFlags.set(Flags.USER_INTERACTOR_AND_REPO_USE_CONTROLLER, true)
+        val scope = TestCoroutineScope()
+        val refreshUsersScheduler =
+            RefreshUsersScheduler(
+                applicationScope = scope,
+                mainDispatcher = IMMEDIATE,
+                repository = userRepository,
+            )
+        val guestUserInteractor =
+            GuestUserInteractor(
+                applicationContext = context,
+                applicationScope = scope,
+                mainDispatcher = IMMEDIATE,
+                backgroundDispatcher = IMMEDIATE,
+                manager = manager,
+                repository = userRepository,
+                deviceProvisionedController = deviceProvisionedController,
+                devicePolicyManager = devicePolicyManager,
+                refreshUsersScheduler = refreshUsersScheduler,
+                uiEventLogger = uiEventLogger,
+            )
+
         underTest =
             UserSwitcherViewModel.Factory(
                     userInteractor =
                         UserInteractor(
+                            applicationContext = context,
                             repository = userRepository,
                             controller = controller,
                             activityStarter = activityStarter,
                             keyguardInteractor =
                                 KeyguardInteractor(
                                     repository = keyguardRepository,
-                                )
+                                ),
+                            featureFlags = featureFlags,
+                            manager = manager,
+                            applicationScope = scope,
+                            telephonyInteractor =
+                                TelephonyInteractor(
+                                    repository = FakeTelephonyRepository(),
+                                ),
+                            broadcastDispatcher = fakeBroadcastDispatcher,
+                            backgroundDispatcher = IMMEDIATE,
+                            activityManager = activityManager,
+                            refreshUsersScheduler = refreshUsersScheduler,
+                            guestUserInteractor = guestUserInteractor,
                         ),
                     powerInteractor =
                         PowerInteractor(
                             repository = powerRepository,
                         ),
+                    featureFlags = featureFlags,
+                    guestUserInteractor = guestUserInteractor,
                 )
                 .create(UserSwitcherViewModel::class.java)
     }
@@ -97,6 +152,7 @@
                         image = USER_IMAGE,
                         isSelected = true,
                         isSelectable = true,
+                        isGuest = false,
                     ),
                     UserModel(
                         id = 1,
@@ -104,6 +160,7 @@
                         image = USER_IMAGE,
                         isSelected = false,
                         isSelectable = true,
+                        isGuest = false,
                     ),
                     UserModel(
                         id = 2,
@@ -111,6 +168,7 @@
                         image = USER_IMAGE,
                         isSelected = false,
                         isSelectable = false,
+                        isGuest = false,
                     ),
                 )
             )
@@ -260,7 +318,7 @@
             job.cancel()
         }
 
-    private fun setUsers(count: Int) {
+    private suspend fun setUsers(count: Int) {
         userRepository.setUsers(
             (0 until count).map { index ->
                 UserModel(
@@ -269,6 +327,7 @@
                     image = USER_IMAGE,
                     isSelected = index == 0,
                     isSelectable = true,
+                    isGuest = false,
                 )
             }
         )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
index 125b362..17d81c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionMonitorTest.java
@@ -73,10 +73,16 @@
                 .addConditions(mConditions);
     }
 
+    private Condition createMockCondition() {
+        final Condition condition = Mockito.mock(Condition.class);
+        when(condition.isConditionSet()).thenReturn(true);
+        return condition;
+    }
+
     @Test
     public void testOverridingCondition() {
-        final Condition overridingCondition = Mockito.mock(Condition.class);
-        final Condition regularCondition = Mockito.mock(Condition.class);
+        final Condition overridingCondition = createMockCondition();
+        final Condition regularCondition = createMockCondition();
         final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class);
 
         final Monitor.Callback referenceCallback = Mockito.mock(Monitor.Callback.class);
@@ -127,9 +133,9 @@
      */
     @Test
     public void testMultipleOverridingConditions() {
-        final Condition overridingCondition = Mockito.mock(Condition.class);
-        final Condition overridingCondition2 = Mockito.mock(Condition.class);
-        final Condition regularCondition = Mockito.mock(Condition.class);
+        final Condition overridingCondition = createMockCondition();
+        final Condition overridingCondition2 = createMockCondition();
+        final Condition regularCondition = createMockCondition();
         final Monitor.Callback callback = Mockito.mock(Monitor.Callback.class);
 
         final Monitor monitor = new Monitor(mExecutor);
@@ -340,4 +346,114 @@
         mExecutor.runAllReady();
         verify(callback).onConditionsChanged(true);
     }
+
+    @Test
+    public void clearCondition_shouldUpdateValue() {
+        mCondition1.fakeUpdateCondition(false);
+        mCondition2.fakeUpdateCondition(true);
+        mCondition3.fakeUpdateCondition(true);
+
+        final Monitor.Callback callback =
+                mock(Monitor.Callback.class);
+        mConditionMonitor.addSubscription(getDefaultBuilder(callback).build());
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(false);
+
+        mCondition1.clearCondition();
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+    }
+
+    @Test
+    public void unsetCondition_shouldNotAffectValue() {
+        final FakeCondition settableCondition = new FakeCondition(null, false);
+        mCondition1.fakeUpdateCondition(true);
+        mCondition2.fakeUpdateCondition(true);
+        mCondition3.fakeUpdateCondition(true);
+
+        final Monitor.Callback callback =
+                mock(Monitor.Callback.class);
+
+        mConditionMonitor.addSubscription(getDefaultBuilder(callback)
+                .addCondition(settableCondition)
+                .build());
+
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+    }
+
+    @Test
+    public void setUnsetCondition_shouldAffectValue() {
+        final FakeCondition settableCondition = new FakeCondition(null, false);
+        mCondition1.fakeUpdateCondition(true);
+        mCondition2.fakeUpdateCondition(true);
+        mCondition3.fakeUpdateCondition(true);
+
+        final Monitor.Callback callback =
+                mock(Monitor.Callback.class);
+
+        mConditionMonitor.addSubscription(getDefaultBuilder(callback)
+                .addCondition(settableCondition)
+                .build());
+
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+        clearInvocations(callback);
+
+        settableCondition.fakeUpdateCondition(false);
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(false);
+        clearInvocations(callback);
+
+
+        settableCondition.clearCondition();
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+    }
+
+    @Test
+    public void clearingOverridingCondition_shouldBeExcluded() {
+        final FakeCondition overridingCondition = new FakeCondition(true, true);
+        mCondition1.fakeUpdateCondition(false);
+        mCondition2.fakeUpdateCondition(false);
+        mCondition3.fakeUpdateCondition(false);
+
+        final Monitor.Callback callback =
+                mock(Monitor.Callback.class);
+
+        mConditionMonitor.addSubscription(getDefaultBuilder(callback)
+                .addCondition(overridingCondition)
+                .build());
+
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+        clearInvocations(callback);
+
+        overridingCondition.clearCondition();
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(false);
+    }
+
+    @Test
+    public void settingUnsetOverridingCondition_shouldBeIncluded() {
+        final FakeCondition overridingCondition = new FakeCondition(null, true);
+        mCondition1.fakeUpdateCondition(false);
+        mCondition2.fakeUpdateCondition(false);
+        mCondition3.fakeUpdateCondition(false);
+
+        final Monitor.Callback callback =
+                mock(Monitor.Callback.class);
+
+        mConditionMonitor.addSubscription(getDefaultBuilder(callback)
+                .addCondition(overridingCondition)
+                .build());
+
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(false);
+        clearInvocations(callback);
+
+        overridingCondition.fakeUpdateCondition(true);
+        mExecutor.runAllReady();
+        verify(callback).onConditionsChanged(true);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java
index 9e0f863..0b53133 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/condition/ConditionTest.java
@@ -133,4 +133,12 @@
         mCondition.fakeUpdateCondition(false);
         verify(callback, never()).onConditionChanged(eq(mCondition));
     }
+
+    @Test
+    public void clearCondition_reportsNotSet() {
+        mCondition.fakeUpdateCondition(false);
+        assertThat(mCondition.isConditionSet()).isTrue();
+        mCondition.clearCondition();
+        assertThat(mCondition.isConditionSet()).isFalse();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
index dead159..e3cd9b2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/view/ViewUtilTest.kt
@@ -1,12 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package com.android.systemui.util.view
 
+import android.graphics.Rect
 import android.view.View
 import android.widget.TextView
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.mockito.any
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
+import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.`when`
 
@@ -25,6 +44,12 @@
         location[0] = VIEW_LEFT
         location[1] = VIEW_TOP
         `when`(view.locationOnScreen).thenReturn(location)
+        doAnswer { invocation ->
+            val pos = invocation.arguments[0] as IntArray
+            pos[0] = VIEW_LEFT
+            pos[1] = VIEW_TOP
+            null
+        }.`when`(view).getLocationInWindow(any())
     }
 
     @Test
@@ -64,6 +89,18 @@
     fun touchIsWithinView_yTooLarge_returnsFalse() {
         assertThat(viewUtil.touchIsWithinView(view, VIEW_LEFT + 1f, VIEW_BOTTOM + 1f)).isFalse()
     }
+
+    @Test
+    fun setRectToViewWindowLocation_rectHasLocation() {
+        val outRect = Rect()
+
+        viewUtil.setRectToViewWindowLocation(view, outRect)
+
+        assertThat(outRect.left).isEqualTo(VIEW_LEFT)
+        assertThat(outRect.right).isEqualTo(VIEW_RIGHT)
+        assertThat(outRect.top).isEqualTo(VIEW_TOP)
+        assertThat(outRect.bottom).isEqualTo(VIEW_BOTTOM)
+    }
 }
 
 private const val VIEW_LEFT = 30
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index aaf2188..3769f52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -46,6 +46,7 @@
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.util.RingerModeLiveData;
@@ -99,6 +100,8 @@
     private KeyguardManager mKeyguardManager;
     @Mock
     private ActivityManager mActivityManager;
+    @Mock
+    private DumpManager mDumpManager;
 
 
     @Before
@@ -121,7 +124,7 @@
                 mBroadcastDispatcher, mRingerModeTracker, mThreadFactory, mAudioManager,
                 mNotificationManager, mVibrator, mIAudioService, mAccessibilityManager,
                 mPackageManager, mWakefullnessLifcycle, mCaptioningManager, mKeyguardManager,
-                mActivityManager, mCallback);
+                mActivityManager, mDumpManager, mCallback);
         mVolumeController.setEnableDialogs(true, true);
     }
 
@@ -202,11 +205,12 @@
                 CaptioningManager captioningManager,
                 KeyguardManager keyguardManager,
                 ActivityManager activityManager,
+                DumpManager dumpManager,
                 C callback) {
             super(context, broadcastDispatcher, ringerModeTracker, theadFactory, audioManager,
                     notificationManager, optionalVibrator, iAudioService, accessibilityManager,
                     packageManager, wakefulnessLifecycle, captioningManager, keyguardManager,
-                    activityManager);
+                    activityManager, dumpManager);
             mCallbacks = callback;
 
             ArgumentCaptor<WakefulnessLifecycle.Observer> observerCaptor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
index 3434376..c254358 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/ImageWallpaperTest.java
@@ -16,14 +16,23 @@
 
 package com.android.systemui.wallpapers;
 
+import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.clearInvocations;
+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.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 static org.mockito.hamcrest.MockitoHamcrest.intThat;
 
 import android.app.WallpaperManager;
 import android.content.Context;
@@ -31,17 +40,25 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.ColorSpace;
+import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Handler;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.Surface;
 import android.view.SurfaceHolder;
+import android.view.WindowManager;
+import android.view.WindowMetrics;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.wallpapers.gl.ImageWallpaperRenderer;
 
 import org.junit.Before;
@@ -56,7 +73,6 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-@Ignore
 public class ImageWallpaperTest extends SysuiTestCase {
     private static final int LOW_BMP_WIDTH = 128;
     private static final int LOW_BMP_HEIGHT = 128;
@@ -66,44 +82,86 @@
     private static final int DISPLAY_HEIGHT = 1080;
 
     @Mock
+    private WindowManager mWindowManager;
+    @Mock
+    private WindowMetrics mWindowMetrics;
+    @Mock
+    private DisplayManager mDisplayManager;
+    @Mock
+    private WallpaperManager mWallpaperManager;
+    @Mock
     private SurfaceHolder mSurfaceHolder;
     @Mock
+    private Surface mSurface;
+    @Mock
     private Context mMockContext;
+
     @Mock
     private Bitmap mWallpaperBitmap;
+    private int mBitmapWidth = 1;
+    private int mBitmapHeight = 1;
+
     @Mock
     private Handler mHandler;
     @Mock
     private FeatureFlags mFeatureFlags;
 
+    FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+    FakeExecutor mFakeMainExecutor = new FakeExecutor(mFakeSystemClock);
+    FakeExecutor mFakeBackgroundExecutor = new FakeExecutor(mFakeSystemClock);
+
     private CountDownLatch mEventCountdown;
 
     @Before
     public void setUp() throws Exception {
         allowTestableLooperAsMainThread();
         MockitoAnnotations.initMocks(this);
-        mEventCountdown = new CountDownLatch(1);
+        //mEventCountdown = new CountDownLatch(1);
 
-        WallpaperManager wallpaperManager = mock(WallpaperManager.class);
+        // set up window manager
+        when(mWindowMetrics.getBounds()).thenReturn(
+                new Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
+        when(mWindowManager.getCurrentWindowMetrics()).thenReturn(mWindowMetrics);
+        when(mMockContext.getSystemService(WindowManager.class)).thenReturn(mWindowManager);
+
+        // set up display manager
+        doNothing().when(mDisplayManager).registerDisplayListener(any(), any());
+        when(mMockContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager);
+
+        // set up bitmap
+        when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB));
+        when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
+        when(mWallpaperBitmap.getWidth()).thenReturn(mBitmapWidth);
+        when(mWallpaperBitmap.getHeight()).thenReturn(mBitmapHeight);
+
+        // set up wallpaper manager
+        when(mWallpaperManager.peekBitmapDimensions()).thenReturn(
+                new Rect(0, 0, mBitmapWidth, mBitmapHeight));
+        when(mWallpaperManager.getBitmap(false)).thenReturn(mWallpaperBitmap);
+        when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(mWallpaperManager);
+
+        // set up surface
+        when(mSurfaceHolder.getSurface()).thenReturn(mSurface);
+        doNothing().when(mSurface).hwuiDestroy();
+
+        // TODO remove code below. Outdated, used in only in old GL tests (that are ignored)
         Resources resources = mock(Resources.class);
-
-        when(mMockContext.getSystemService(WallpaperManager.class)).thenReturn(wallpaperManager);
-        when(mMockContext.getResources()).thenReturn(resources);
         when(resources.getConfiguration()).thenReturn(mock(Configuration.class));
-
+        when(mMockContext.getResources()).thenReturn(resources);
         DisplayInfo displayInfo = new DisplayInfo();
         displayInfo.logicalWidth = DISPLAY_WIDTH;
         displayInfo.logicalHeight = DISPLAY_HEIGHT;
         when(mMockContext.getDisplay()).thenReturn(
                 new Display(mock(DisplayManagerGlobal.class), 0, displayInfo, (Resources) null));
+    }
 
-        when(wallpaperManager.getBitmap(false)).thenReturn(mWallpaperBitmap);
-        when(mWallpaperBitmap.getColorSpace()).thenReturn(ColorSpace.get(ColorSpace.Named.SRGB));
-        when(mWallpaperBitmap.getConfig()).thenReturn(Bitmap.Config.ARGB_8888);
+    private void setBitmapDimensions(int bitmapWidth, int bitmapHeight) {
+        mBitmapWidth = bitmapWidth;
+        mBitmapHeight = bitmapHeight;
     }
 
     private ImageWallpaper createImageWallpaper() {
-        return new ImageWallpaper(mFeatureFlags) {
+        return new ImageWallpaper(mFeatureFlags, mFakeBackgroundExecutor, mFakeMainExecutor) {
             @Override
             public Engine onCreateEngine() {
                 return new GLEngine(mHandler) {
@@ -130,6 +188,7 @@
     }
 
     @Test
+    @Ignore
     public void testBitmapWallpaper_normal() {
         // Will use a image wallpaper with dimensions DISPLAY_WIDTH x DISPLAY_WIDTH.
         // Then we expect the surface size will be also DISPLAY_WIDTH x DISPLAY_WIDTH.
@@ -140,6 +199,7 @@
     }
 
     @Test
+    @Ignore
     public void testBitmapWallpaper_low_resolution() {
         // Will use a image wallpaper with dimensions BMP_WIDTH x BMP_HEIGHT.
         // Then we expect the surface size will be also BMP_WIDTH x BMP_HEIGHT.
@@ -150,6 +210,7 @@
     }
 
     @Test
+    @Ignore
     public void testBitmapWallpaper_too_small() {
         // Will use a image wallpaper with dimensions INVALID_BMP_WIDTH x INVALID_BMP_HEIGHT.
         // Then we expect the surface size will be also MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT.
@@ -166,8 +227,7 @@
 
         ImageWallpaper.GLEngine engineSpy = spy(wallpaperEngine);
 
-        when(mWallpaperBitmap.getWidth()).thenReturn(bmpWidth);
-        when(mWallpaperBitmap.getHeight()).thenReturn(bmpHeight);
+        setBitmapDimensions(bmpWidth, bmpHeight);
 
         ImageWallpaperRenderer renderer = new ImageWallpaperRenderer(mMockContext);
         doReturn(renderer).when(engineSpy).getRendererInstance();
@@ -177,4 +237,116 @@
         assertWithMessage("setFixedSizeAllowed should have been called.").that(
                 mEventCountdown.getCount()).isEqualTo(0);
     }
+
+
+    private ImageWallpaper createImageWallpaperCanvas() {
+        return new ImageWallpaper(mFeatureFlags, mFakeBackgroundExecutor, mFakeMainExecutor) {
+            @Override
+            public Engine onCreateEngine() {
+                return new CanvasEngine() {
+                    @Override
+                    public Context getDisplayContext() {
+                        return mMockContext;
+                    }
+
+                    @Override
+                    public SurfaceHolder getSurfaceHolder() {
+                        return mSurfaceHolder;
+                    }
+
+                    @Override
+                    public void setFixedSizeAllowed(boolean allowed) {
+                        super.setFixedSizeAllowed(allowed);
+                        assertWithMessage("mFixedSizeAllowed should be true").that(
+                                allowed).isTrue();
+                    }
+                };
+            }
+        };
+    }
+
+    private ImageWallpaper.CanvasEngine getSpyEngine() {
+        ImageWallpaper imageWallpaper = createImageWallpaperCanvas();
+        ImageWallpaper.CanvasEngine engine =
+                (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
+        ImageWallpaper.CanvasEngine spyEngine = spy(engine);
+        doNothing().when(spyEngine).drawFrameOnCanvas(any(Bitmap.class));
+        doNothing().when(spyEngine).reportEngineShown(anyBoolean());
+        doAnswer(invocation -> {
+            ((ImageWallpaper.CanvasEngine) invocation.getMock()).onMiniBitmapUpdated();
+            return null;
+        }).when(spyEngine).recomputeColorExtractorMiniBitmap();
+        return spyEngine;
+    }
+
+    @Test
+    public void testMinSurface() {
+
+        // test that the surface is always at least MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT
+        testMinSurfaceHelper(8, 8);
+        testMinSurfaceHelper(100, 2000);
+        testMinSurfaceHelper(200, 1);
+        testMinSurfaceHelper(0, 1);
+        testMinSurfaceHelper(1, 0);
+        testMinSurfaceHelper(0, 0);
+    }
+
+    private void testMinSurfaceHelper(int bitmapWidth, int bitmapHeight) {
+
+        clearInvocations(mSurfaceHolder);
+        setBitmapDimensions(bitmapWidth, bitmapHeight);
+
+        ImageWallpaper imageWallpaper = createImageWallpaperCanvas();
+        ImageWallpaper.CanvasEngine engine =
+                (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
+        engine.onCreate(mSurfaceHolder);
+
+        verify(mSurfaceHolder, times(1)).setFixedSize(
+                intThat(greaterThanOrEqualTo(ImageWallpaper.CanvasEngine.MIN_SURFACE_WIDTH)),
+                intThat(greaterThanOrEqualTo(ImageWallpaper.CanvasEngine.MIN_SURFACE_HEIGHT)));
+    }
+
+    @Test
+    public void testZeroBitmap() {
+        // test that a frame is never drawn with a 0 bitmap
+        testZeroBitmapHelper(0, 1);
+        testZeroBitmapHelper(1, 0);
+        testZeroBitmapHelper(0, 0);
+    }
+
+    private void testZeroBitmapHelper(int bitmapWidth, int bitmapHeight) {
+
+        clearInvocations(mSurfaceHolder);
+        setBitmapDimensions(bitmapWidth, bitmapHeight);
+
+        ImageWallpaper imageWallpaper = createImageWallpaperCanvas();
+        ImageWallpaper.CanvasEngine engine =
+                (ImageWallpaper.CanvasEngine) imageWallpaper.onCreateEngine();
+        ImageWallpaper.CanvasEngine spyEngine = spy(engine);
+        spyEngine.onCreate(mSurfaceHolder);
+        spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
+        verify(spyEngine, never()).drawFrameOnCanvas(any());
+    }
+
+    @Test
+    public void testLoadDrawAndUnloadBitmap() {
+        setBitmapDimensions(LOW_BMP_WIDTH, LOW_BMP_HEIGHT);
+
+        ImageWallpaper.CanvasEngine spyEngine = getSpyEngine();
+        spyEngine.onCreate(mSurfaceHolder);
+        spyEngine.onSurfaceRedrawNeeded(mSurfaceHolder);
+        assertThat(mFakeBackgroundExecutor.numPending()).isAtLeast(1);
+
+        int n = 0;
+        while (mFakeBackgroundExecutor.numPending() + mFakeMainExecutor.numPending() >= 1) {
+            n++;
+            assertThat(n).isAtMost(10);
+            mFakeBackgroundExecutor.runNextReady();
+            mFakeMainExecutor.runNextReady();
+            mFakeSystemClock.advanceTime(1000);
+        }
+
+        verify(spyEngine, times(1)).drawFrameOnCanvas(mWallpaperBitmap);
+        assertThat(spyEngine.isBitmapLoaded()).isFalse();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/ImageCanvasWallpaperRendererTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/ImageCanvasWallpaperRendererTest.java
deleted file mode 100644
index 93f4f82..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/ImageCanvasWallpaperRendererTest.java
+++ /dev/null
@@ -1,133 +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.wallpapers.canvas;
-
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.clearInvocations;
-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 static org.mockito.hamcrest.MockitoHamcrest.intThat;
-
-import android.graphics.Bitmap;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.view.DisplayInfo;
-import android.view.SurfaceHolder;
-
-import com.android.systemui.SysuiTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
-public class ImageCanvasWallpaperRendererTest extends SysuiTestCase {
-
-    private static final int MOBILE_DISPLAY_WIDTH = 720;
-    private static final int MOBILE_DISPLAY_HEIGHT = 1600;
-
-    @Mock
-    private SurfaceHolder mMockSurfaceHolder;
-
-    @Mock
-    private DisplayInfo mMockDisplayInfo;
-
-    @Mock
-    private Bitmap mMockBitmap;
-
-    @Before
-    public void setUp() throws Exception {
-        allowTestableLooperAsMainThread();
-        MockitoAnnotations.initMocks(this);
-    }
-
-    private void setDimensions(
-            int bitmapWidth, int bitmapHeight,
-            int displayWidth, int displayHeight) {
-        when(mMockBitmap.getWidth()).thenReturn(bitmapWidth);
-        when(mMockBitmap.getHeight()).thenReturn(bitmapHeight);
-        mMockDisplayInfo.logicalWidth = displayWidth;
-        mMockDisplayInfo.logicalHeight = displayHeight;
-    }
-
-    private void testMinDimensions(
-            int bitmapWidth, int bitmapHeight) {
-
-        clearInvocations(mMockSurfaceHolder);
-        setDimensions(bitmapWidth, bitmapHeight,
-                ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_WIDTH,
-                ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_HEIGHT);
-
-        ImageCanvasWallpaperRenderer renderer =
-                new ImageCanvasWallpaperRenderer(mMockSurfaceHolder);
-        renderer.drawFrame(mMockBitmap, true);
-
-        verify(mMockSurfaceHolder, times(1)).setFixedSize(
-                intThat(greaterThanOrEqualTo(ImageCanvasWallpaperRenderer.MIN_SURFACE_WIDTH)),
-                intThat(greaterThanOrEqualTo(ImageCanvasWallpaperRenderer.MIN_SURFACE_HEIGHT)));
-    }
-
-    @Test
-    public void testMinSurface() {
-        // test that the surface is always at least MIN_SURFACE_WIDTH x MIN_SURFACE_HEIGHT
-        testMinDimensions(8, 8);
-
-        testMinDimensions(100, 2000);
-
-        testMinDimensions(200, 1);
-    }
-
-    private void testZeroDimensions(int bitmapWidth, int bitmapHeight) {
-
-        clearInvocations(mMockSurfaceHolder);
-        setDimensions(bitmapWidth, bitmapHeight,
-                ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_WIDTH,
-                ImageCanvasWallpaperRendererTest.MOBILE_DISPLAY_HEIGHT);
-
-        ImageCanvasWallpaperRenderer renderer =
-                new ImageCanvasWallpaperRenderer(mMockSurfaceHolder);
-        ImageCanvasWallpaperRenderer spyRenderer = spy(renderer);
-        spyRenderer.drawFrame(mMockBitmap, true);
-
-        verify(mMockSurfaceHolder, never()).setFixedSize(anyInt(), anyInt());
-        verify(spyRenderer, never()).drawWallpaperWithCanvas(any());
-    }
-
-    @Test
-    public void testZeroBitmap() {
-        // test that updateSurfaceSize is not called with a bitmap of width 0 or height 0
-        testZeroDimensions(
-                0, 1
-        );
-
-        testZeroDimensions(1, 0
-        );
-
-        testZeroDimensions(0, 0
-        );
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/WallpaperColorExtractorTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/WallpaperColorExtractorTest.java
new file mode 100644
index 0000000..76bff1d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallpapers/canvas/WallpaperColorExtractorTest.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.wallpapers.canvas;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+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.when;
+
+import android.app.WallpaperColors;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class WallpaperColorExtractorTest extends SysuiTestCase {
+    private static final int LOW_BMP_WIDTH = 128;
+    private static final int LOW_BMP_HEIGHT = 128;
+    private static final int HIGH_BMP_WIDTH = 3000;
+    private static final int HIGH_BMP_HEIGHT = 4000;
+    private static final int VERY_LOW_BMP_WIDTH = 1;
+    private static final int VERY_LOW_BMP_HEIGHT = 1;
+    private static final int DISPLAY_WIDTH = 1920;
+    private static final int DISPLAY_HEIGHT = 1080;
+
+    private static final int PAGES_LOW = 4;
+    private static final int PAGES_HIGH = 7;
+
+    private static final int MIN_AREAS = 4;
+    private static final int MAX_AREAS = 10;
+
+    private int mMiniBitmapWidth;
+    private int mMiniBitmapHeight;
+
+    @Mock
+    private Executor mBackgroundExecutor;
+
+    private int mColorsProcessed;
+    private int mMiniBitmapUpdatedCount;
+    private int mActivatedCount;
+    private int mDeactivatedCount;
+
+    @Before
+    public void setUp() throws Exception {
+        allowTestableLooperAsMainThread();
+        MockitoAnnotations.initMocks(this);
+        doAnswer(invocation ->  {
+            ((Runnable) invocation.getArgument(0)).run();
+            return null;
+        }).when(mBackgroundExecutor).execute(any(Runnable.class));
+    }
+
+    private void resetCounters() {
+        mColorsProcessed = 0;
+        mMiniBitmapUpdatedCount = 0;
+        mActivatedCount = 0;
+        mDeactivatedCount = 0;
+    }
+
+    private Bitmap getMockBitmap(int width, int height) {
+        Bitmap bitmap = mock(Bitmap.class);
+        when(bitmap.getWidth()).thenReturn(width);
+        when(bitmap.getHeight()).thenReturn(height);
+        return bitmap;
+    }
+
+    private WallpaperColorExtractor getSpyWallpaperColorExtractor() {
+
+        WallpaperColorExtractor wallpaperColorExtractor = new WallpaperColorExtractor(
+                mBackgroundExecutor,
+                new WallpaperColorExtractor.WallpaperColorExtractorCallback() {
+                    @Override
+                    public void onColorsProcessed(List<RectF> regions,
+                            List<WallpaperColors> colors) {
+                        assertThat(regions.size()).isEqualTo(colors.size());
+                        mColorsProcessed += regions.size();
+                    }
+
+                    @Override
+                    public void onMiniBitmapUpdated() {
+                        mMiniBitmapUpdatedCount++;
+                    }
+
+                    @Override
+                    public void onActivated() {
+                        mActivatedCount++;
+                    }
+
+                    @Override
+                    public void onDeactivated() {
+                        mDeactivatedCount++;
+                    }
+                });
+        WallpaperColorExtractor spyWallpaperColorExtractor = spy(wallpaperColorExtractor);
+
+        doAnswer(invocation -> {
+            mMiniBitmapWidth = invocation.getArgument(1);
+            mMiniBitmapHeight = invocation.getArgument(2);
+            return getMockBitmap(mMiniBitmapWidth, mMiniBitmapHeight);
+        }).when(spyWallpaperColorExtractor).createMiniBitmap(any(Bitmap.class), anyInt(), anyInt());
+
+
+        doAnswer(invocation -> getMockBitmap(
+                        invocation.getArgument(1),
+                        invocation.getArgument(2)))
+                .when(spyWallpaperColorExtractor)
+                .createMiniBitmap(any(Bitmap.class), anyInt(), anyInt());
+
+        doReturn(new WallpaperColors(Color.valueOf(0), Color.valueOf(0), Color.valueOf(0)))
+                .when(spyWallpaperColorExtractor).getLocalWallpaperColors(any(Rect.class));
+
+        return spyWallpaperColorExtractor;
+    }
+
+    private RectF randomArea() {
+        float width = (float) Math.random();
+        float startX = (float) (Math.random() * (1 - width));
+        float height = (float) Math.random();
+        float startY = (float) (Math.random() * (1 - height));
+        return new RectF(startX, startY, startX + width, startY + height);
+    }
+
+    private List<RectF> listOfRandomAreas(int min, int max) {
+        int nAreas = randomBetween(min, max);
+        List<RectF> result = new ArrayList<>();
+        for (int i = 0; i < nAreas; i++) {
+            result.add(randomArea());
+        }
+        return result;
+    }
+
+    private int randomBetween(int minIncluded, int maxIncluded) {
+        return (int) (Math.random() * ((maxIncluded - minIncluded) + 1)) + minIncluded;
+    }
+
+    /**
+     * Test that for bitmaps of random dimensions, the mini bitmap is always created
+     * with either a width <= SMALL_SIDE or a height <= SMALL_SIDE
+     */
+    @Test
+    public void testMiniBitmapCreation() {
+        WallpaperColorExtractor spyWallpaperColorExtractor = getSpyWallpaperColorExtractor();
+        int nSimulations = 10;
+        for (int i = 0; i < nSimulations; i++) {
+            resetCounters();
+            int width = randomBetween(LOW_BMP_WIDTH, HIGH_BMP_WIDTH);
+            int height = randomBetween(LOW_BMP_HEIGHT, HIGH_BMP_HEIGHT);
+            Bitmap bitmap = getMockBitmap(width, height);
+            spyWallpaperColorExtractor.onBitmapChanged(bitmap);
+
+            assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
+            assertThat(Math.min(mMiniBitmapWidth, mMiniBitmapHeight))
+                    .isAtMost(WallpaperColorExtractor.SMALL_SIDE);
+        }
+    }
+
+    /**
+     * Test that for bitmaps with both width and height <= SMALL_SIDE,
+     * the mini bitmap is always created with both width and height <= SMALL_SIDE
+     */
+    @Test
+    public void testSmallMiniBitmapCreation() {
+        WallpaperColorExtractor spyWallpaperColorExtractor = getSpyWallpaperColorExtractor();
+        int nSimulations = 10;
+        for (int i = 0; i < nSimulations; i++) {
+            resetCounters();
+            int width = randomBetween(VERY_LOW_BMP_WIDTH, LOW_BMP_WIDTH);
+            int height = randomBetween(VERY_LOW_BMP_HEIGHT, LOW_BMP_HEIGHT);
+            Bitmap bitmap = getMockBitmap(width, height);
+            spyWallpaperColorExtractor.onBitmapChanged(bitmap);
+
+            assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
+            assertThat(Math.max(mMiniBitmapWidth, mMiniBitmapHeight))
+                    .isAtMost(WallpaperColorExtractor.SMALL_SIDE);
+        }
+    }
+
+    /**
+     * Test that for a new color extractor with information
+     * (number of pages, display dimensions, wallpaper bitmap) given in random order,
+     * the colors are processed and all the callbacks are properly executed.
+     */
+    @Test
+    public void testNewColorExtraction() {
+        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
+
+        int nSimulations = 10;
+        for (int i = 0; i < nSimulations; i++) {
+            resetCounters();
+            WallpaperColorExtractor spyWallpaperColorExtractor = getSpyWallpaperColorExtractor();
+            List<RectF> regions = listOfRandomAreas(MIN_AREAS, MAX_AREAS);
+            int nPages = randomBetween(PAGES_LOW, PAGES_HIGH);
+            List<Runnable> tasks = Arrays.asList(
+                    () -> spyWallpaperColorExtractor.onPageChanged(nPages),
+                    () -> spyWallpaperColorExtractor.onBitmapChanged(bitmap),
+                    () -> spyWallpaperColorExtractor.setDisplayDimensions(
+                            DISPLAY_WIDTH, DISPLAY_HEIGHT),
+                    () -> spyWallpaperColorExtractor.addLocalColorsAreas(
+                            regions));
+            Collections.shuffle(tasks);
+            tasks.forEach(Runnable::run);
+
+            assertThat(mActivatedCount).isEqualTo(1);
+            assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
+            assertThat(mColorsProcessed).isEqualTo(regions.size());
+
+            spyWallpaperColorExtractor.removeLocalColorAreas(regions);
+            assertThat(mDeactivatedCount).isEqualTo(1);
+        }
+    }
+
+    /**
+     * Test that the method removeLocalColorAreas behaves properly and does not call
+     * the onDeactivated callback unless all color areas are removed.
+     */
+    @Test
+    public void testRemoveColors() {
+        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
+        int nSimulations = 10;
+        for (int i = 0; i < nSimulations; i++) {
+            resetCounters();
+            WallpaperColorExtractor spyWallpaperColorExtractor = getSpyWallpaperColorExtractor();
+            List<RectF> regions1 = listOfRandomAreas(MIN_AREAS / 2, MAX_AREAS / 2);
+            List<RectF> regions2 = listOfRandomAreas(MIN_AREAS / 2, MAX_AREAS / 2);
+            List<RectF> regions = new ArrayList<>();
+            regions.addAll(regions1);
+            regions.addAll(regions2);
+            int nPages = randomBetween(PAGES_LOW, PAGES_HIGH);
+            List<Runnable> tasks = Arrays.asList(
+                    () -> spyWallpaperColorExtractor.onPageChanged(nPages),
+                    () -> spyWallpaperColorExtractor.onBitmapChanged(bitmap),
+                    () -> spyWallpaperColorExtractor.setDisplayDimensions(
+                            DISPLAY_WIDTH, DISPLAY_HEIGHT),
+                    () -> spyWallpaperColorExtractor.removeLocalColorAreas(regions1));
+
+            spyWallpaperColorExtractor.addLocalColorsAreas(regions);
+            assertThat(mActivatedCount).isEqualTo(1);
+            Collections.shuffle(tasks);
+            tasks.forEach(Runnable::run);
+
+            assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
+            assertThat(mDeactivatedCount).isEqualTo(0);
+            spyWallpaperColorExtractor.removeLocalColorAreas(regions2);
+            assertThat(mDeactivatedCount).isEqualTo(1);
+        }
+    }
+
+    /**
+     * Test that if we change some information (wallpaper bitmap, number of pages),
+     * the colors are correctly recomputed.
+     * Test that if we remove some color areas in the middle of the process,
+     * only the remaining areas are recomputed.
+     */
+    @Test
+    public void testRecomputeColorExtraction() {
+        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
+        WallpaperColorExtractor spyWallpaperColorExtractor = getSpyWallpaperColorExtractor();
+        List<RectF> regions1 = listOfRandomAreas(MIN_AREAS / 2, MAX_AREAS / 2);
+        List<RectF> regions2 = listOfRandomAreas(MIN_AREAS / 2, MAX_AREAS / 2);
+        List<RectF> regions = new ArrayList<>();
+        regions.addAll(regions1);
+        regions.addAll(regions2);
+        spyWallpaperColorExtractor.addLocalColorsAreas(regions);
+        assertThat(mActivatedCount).isEqualTo(1);
+        int nPages = PAGES_LOW;
+        spyWallpaperColorExtractor.onBitmapChanged(bitmap);
+        spyWallpaperColorExtractor.onPageChanged(nPages);
+        spyWallpaperColorExtractor.setDisplayDimensions(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+
+        int nSimulations = 20;
+        for (int i = 0; i < nSimulations; i++) {
+            resetCounters();
+
+            // verify that if we remove some regions, they are not recomputed after other changes
+            if (i == nSimulations / 2) {
+                regions.removeAll(regions2);
+                spyWallpaperColorExtractor.removeLocalColorAreas(regions2);
+            }
+
+            if (Math.random() >= 0.5) {
+                int nPagesNew = randomBetween(PAGES_LOW, PAGES_HIGH);
+                if (nPagesNew == nPages) continue;
+                nPages = nPagesNew;
+                spyWallpaperColorExtractor.onPageChanged(nPagesNew);
+            } else {
+                Bitmap newBitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
+                spyWallpaperColorExtractor.onBitmapChanged(newBitmap);
+                assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
+            }
+            assertThat(mColorsProcessed).isEqualTo(regions.size());
+        }
+        spyWallpaperColorExtractor.removeLocalColorAreas(regions);
+        assertThat(mDeactivatedCount).isEqualTo(1);
+    }
+
+    @Test
+    public void testCleanUp() {
+        resetCounters();
+        Bitmap bitmap = getMockBitmap(HIGH_BMP_WIDTH, HIGH_BMP_HEIGHT);
+        doNothing().when(bitmap).recycle();
+        WallpaperColorExtractor spyWallpaperColorExtractor = getSpyWallpaperColorExtractor();
+        spyWallpaperColorExtractor.onPageChanged(PAGES_LOW);
+        spyWallpaperColorExtractor.onBitmapChanged(bitmap);
+        assertThat(mMiniBitmapUpdatedCount).isEqualTo(1);
+        spyWallpaperColorExtractor.cleanUp();
+        spyWallpaperColorExtractor.addLocalColorsAreas(listOfRandomAreas(MIN_AREAS, MAX_AREAS));
+        assertThat(mColorsProcessed).isEqualTo(0);
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index c83189d..fa3cc99 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -84,9 +84,14 @@
         initializer.init(true);
         mDependency = new TestableDependency(initializer.getSysUIComponent().createDependency());
         Dependency.setInstance(mDependency);
-        mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class),
-                mock(Executor.class), mock(DumpManager.class),
-                mock(BroadcastDispatcherLogger.class), mock(UserTracker.class));
+        mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(
+                mContext,
+                mContext.getMainExecutor(),
+                mock(Looper.class),
+                mock(Executor.class),
+                mock(DumpManager.class),
+                mock(BroadcastDispatcherLogger.class),
+                mock(UserTracker.class));
 
         mRealInstrumentation = InstrumentationRegistry.getInstrumentation();
         Instrumentation inst = spy(mRealInstrumentation);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index 53dcc8d..52e0c982 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -32,15 +32,25 @@
 
 class FakeBroadcastDispatcher(
     context: SysuiTestableContext,
-    looper: Looper,
-    executor: Executor,
+    mainExecutor: Executor,
+    broadcastRunningLooper: Looper,
+    broadcastRunningExecutor: Executor,
     dumpManager: DumpManager,
     logger: BroadcastDispatcherLogger,
     userTracker: UserTracker
-) : BroadcastDispatcher(
-    context, looper, executor, dumpManager, logger, userTracker, PendingRemovalStore(logger)) {
+) :
+    BroadcastDispatcher(
+        context,
+        mainExecutor,
+        broadcastRunningLooper,
+        broadcastRunningExecutor,
+        dumpManager,
+        logger,
+        userTracker,
+        PendingRemovalStore(logger)
+    ) {
 
-    private val registeredReceivers = ArraySet<BroadcastReceiver>()
+    val registeredReceivers = ArraySet<BroadcastReceiver>()
 
     override fun registerReceiverWithHandler(
         receiver: BroadcastReceiver,
@@ -78,4 +88,4 @@
         }
         registeredReceivers.clear()
     }
-}
\ No newline at end of file
+}
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 c56fdb1..5d52be2 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,6 +16,8 @@
 
 package com.android.systemui.flags
 
+import java.io.PrintWriter
+
 class FakeFeatureFlags : FeatureFlags {
     private val booleanFlags = mutableMapOf<Int, Boolean>()
     private val stringFlags = mutableMapOf<Int, String>()
@@ -106,6 +108,10 @@
         }
     }
 
+    override fun dump(writer: PrintWriter, args: Array<out String>?) {
+        // no-op
+    }
+
     private fun flagName(flagId: Int): String {
         return knownFlagNames[flagId] ?: "UNKNOWN(id=$flagId)"
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 42b434a..725b1f4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -44,6 +44,10 @@
     private val _dozeAmount = MutableStateFlow(0f)
     override val dozeAmount: Flow<Float> = _dozeAmount
 
+    override fun isKeyguardShowing(): Boolean {
+        return _isKeyguardShowing.value
+    }
+
     override fun setAnimateDozingTransitions(animate: Boolean) {
         _animateBottomAreaDozingTransitions.tryEmit(animate)
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index b2b1764..9726bf8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -26,20 +26,24 @@
 
 /** A fake [UserTracker] to be used in tests. */
 class FakeUserTracker(
-    userId: Int = 0,
-    userHandle: UserHandle = UserHandle.of(userId),
-    userInfo: UserInfo = mock(),
-    userProfiles: List<UserInfo> = emptyList(),
+    private var _userId: Int = 0,
+    private var _userHandle: UserHandle = UserHandle.of(_userId),
+    private var _userInfo: UserInfo = mock(),
+    private var _userProfiles: List<UserInfo> = emptyList(),
     userContentResolver: ContentResolver = MockContentResolver(),
     userContext: Context = mock(),
     private val onCreateCurrentUserContext: (Context) -> Context = { mock() },
 ) : UserTracker {
     val callbacks = mutableListOf<UserTracker.Callback>()
 
-    override val userId: Int = userId
-    override val userHandle: UserHandle = userHandle
-    override val userInfo: UserInfo = userInfo
-    override val userProfiles: List<UserInfo> = userProfiles
+    override val userId: Int
+        get() = _userId
+    override val userHandle: UserHandle
+        get() = _userHandle
+    override val userInfo: UserInfo
+        get() = _userInfo
+    override val userProfiles: List<UserInfo>
+        get() = _userProfiles
 
     override val userContentResolver: ContentResolver = userContentResolver
     override val userContext: Context = userContext
@@ -55,4 +59,13 @@
     override fun createCurrentUserContext(context: Context): Context {
         return onCreateCurrentUserContext(context)
     }
+
+    fun set(userInfos: List<UserInfo>, selectedUserIndex: Int) {
+        _userProfiles = userInfos
+        _userInfo = userInfos[selectedUserIndex]
+        _userId = _userInfo.id
+        _userHandle = UserHandle.of(_userId)
+
+        callbacks.forEach { it.onUserChanged(_userId, userContext) }
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.kt
new file mode 100644
index 0000000..59f24ef
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/telephony/data/repository/FakeTelephonyRepository.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.telephony.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeTelephonyRepository : TelephonyRepository {
+
+    private val _callState = MutableStateFlow(0)
+    override val callState: Flow<Int> = _callState.asStateFlow()
+
+    fun setCallState(value: Int) {
+        _callState.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
index 20f1e36..4df8aa4 100644
--- 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
@@ -17,12 +17,18 @@
 
 package com.android.systemui.user.data.repository
 
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import com.android.systemui.user.data.model.UserSwitcherSettingsModel
 import com.android.systemui.user.shared.model.UserActionModel
 import com.android.systemui.user.shared.model.UserModel
+import java.util.concurrent.atomic.AtomicBoolean
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.yield
 
 class FakeUserRepository : UserRepository {
 
@@ -34,21 +40,71 @@
     private val _actions = MutableStateFlow<List<UserActionModel>>(emptyList())
     override val actions: Flow<List<UserActionModel>> = _actions.asStateFlow()
 
+    private val _userSwitcherSettings = MutableStateFlow(UserSwitcherSettingsModel())
+    override val userSwitcherSettings: Flow<UserSwitcherSettingsModel> =
+        _userSwitcherSettings.asStateFlow()
+
+    private val _userInfos = MutableStateFlow<List<UserInfo>>(emptyList())
+    override val userInfos: Flow<List<UserInfo>> = _userInfos.asStateFlow()
+
+    private val _selectedUserInfo = MutableStateFlow<UserInfo?>(null)
+    override val selectedUserInfo: Flow<UserInfo> = _selectedUserInfo.filterNotNull()
+
+    override var lastSelectedNonGuestUserId: Int = UserHandle.USER_SYSTEM
+
     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
+
+    override var isGuestUserResetting: Boolean = false
+
+    override val isGuestUserCreationScheduled = AtomicBoolean()
+
+    override var secondaryUserId: Int = UserHandle.USER_NULL
+
+    override var isRefreshUsersPaused: Boolean = false
+
+    var refreshUsersCallCount: Int = 0
+        private set
+
+    override fun refreshUsers() {
+        refreshUsersCallCount++
+    }
+
+    override fun getSelectedUserInfo(): UserInfo {
+        return checkNotNull(_selectedUserInfo.value)
+    }
+
+    override fun isSimpleUserSwitcher(): Boolean {
+        return _userSwitcherSettings.value.isSimpleUserSwitcher
+    }
+
+    fun setUserInfos(infos: List<UserInfo>) {
+        _userInfos.value = infos
+    }
+
+    suspend fun setSelectedUserInfo(userInfo: UserInfo) {
+        check(_userInfos.value.contains(userInfo)) {
+            "Cannot select the following user, it is not in the list of user infos: $userInfo!"
+        }
+
+        _selectedUserInfo.value = userInfo
+        yield()
+    }
+
+    suspend fun setSettings(settings: UserSwitcherSettingsModel) {
+        _userSwitcherSettings.value = settings
+        yield()
+    }
 
     fun setUsers(models: List<UserModel>) {
         _users.value = models
     }
 
-    fun setSelectedUser(userId: Int) {
+    suspend 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!"
         }
@@ -62,6 +118,7 @@
                 }
             }
         )
+        yield()
     }
 
     fun setActions(models: List<UserActionModel>) {
@@ -75,8 +132,4 @@
     fun setGuestUserAutoCreated(value: Boolean) {
         _isGuestUserAutoCreated = value
     }
-
-    fun setGuestUserResetting(value: Boolean) {
-        _isGuestUserResetting = value
-    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/condition/FakeCondition.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/condition/FakeCondition.java
index 9d5ccbe..1353ad2 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/condition/FakeCondition.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/condition/FakeCondition.java
@@ -21,6 +21,14 @@
  * condition fulfillment.
  */
 public class FakeCondition extends Condition {
+    FakeCondition() {
+        super();
+    }
+
+    FakeCondition(Boolean initialValue, Boolean overriding) {
+        super(initialValue, overriding);
+    }
+
     @Override
     public void start() {}
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
index 2be67ed..23c7a61 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java
@@ -70,6 +70,10 @@
     }
 
     @Override
+    public void setNewMobileIconSubIds(List<Integer> subIds) {
+    }
+
+    @Override
     public void setCallStrengthIcons(String slot, List<CallIndicatorIconState> states) {
     }
 
diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index 2ab28c6..043aff6 100644
--- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -203,6 +203,6 @@
 private const val TAG = "PhysicsBasedUnfoldTransitionProgressProvider"
 private const val DEBUG = true
 
-private const val SPRING_STIFFNESS = 200.0f
+private const val SPRING_STIFFNESS = 600.0f
 private const val MINIMAL_VISIBLE_CHANGE = 0.001f
 private const val FINAL_HINGE_ANGLE_POSITION = 165f
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index 94a7909..f86a5d6 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="prompt" msgid="3183836924226407828">"Solicitare de conexiune"</string>
     <string name="warning" msgid="809658604548412033">"<xliff:g id="APP">%s</xliff:g> dorește să configureze o conexiune VPN care să îi permită să monitorizeze traficul în rețea. Acceptă numai dacă ai încredere în sursă. Când conexiunea VPN e activă, &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; se afișează în partea de sus a ecranului."</string>
-    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> solicită permisiunea de a configura o conexiune VPN care să îi permită să monitorizeze traficul de rețea. Acceptați numai dacă aveți încredere în sursă. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; va apărea pe ecran atunci când conexiunea VPN este activă."</string>
+    <string name="warning" product="tv" msgid="5188957997628124947">"<xliff:g id="APP">%s</xliff:g> solicită permisiunea de a configura o conexiune VPN care să îi permită să monitorizeze traficul de rețea. Acceptă numai dacă ai încredere în sursă. &lt;br /&gt; &lt;br /&gt; &lt;img src=vpn_icon /&gt; va apărea pe ecran când conexiunea VPN e activă."</string>
     <string name="legacy_title" msgid="192936250066580964">"VPN este conectat"</string>
     <string name="session" msgid="6470628549473641030">"Sesiune:"</string>
     <string name="duration" msgid="3584782459928719435">"Durată:"</string>
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index abc4937..a94e4b9 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -1152,6 +1152,9 @@
     }
 
     private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) {
+        if (packageInfo == null) {
+            return;
+        }
         if (containsEither(packageInfo.requestedPermissions,
                 android.Manifest.permission.RUN_IN_BACKGROUND,
                 android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
diff --git a/services/companion/java/com/android/server/companion/PackageUtils.java b/services/companion/java/com/android/server/companion/PackageUtils.java
index f523773..451a700 100644
--- a/services/companion/java/com/android/server/companion/PackageUtils.java
+++ b/services/companion/java/com/android/server/companion/PackageUtils.java
@@ -54,12 +54,19 @@
     private static final String PROPERTY_PRIMARY_TAG =
             "android.companion.PROPERTY_PRIMARY_COMPANION_DEVICE_SERVICE";
 
-    static @Nullable PackageInfo getPackageInfo(@NonNull Context context,
+    @Nullable
+    static PackageInfo getPackageInfo(@NonNull Context context,
             @UserIdInt int userId, @NonNull String packageName) {
         final PackageManager pm = context.getPackageManager();
         final PackageInfoFlags flags = PackageInfoFlags.of(GET_PERMISSIONS | GET_CONFIGURATIONS);
-        return Binder.withCleanCallingIdentity(() ->
-                pm.getPackageInfoAsUser(packageName, flags , userId));
+        return Binder.withCleanCallingIdentity(() -> {
+            try {
+                return pm.getPackageInfoAsUser(packageName, flags, userId);
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.e(TAG, "Package [" + packageName + "] is not found.");
+                return null;
+            }
+        });
     }
 
     static void enforceUsesCompanionDeviceFeature(@NonNull Context context,
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..33f1b42 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -184,13 +184,21 @@
     @MainThread
     private void startScan() {
         enforceInitialized();
-        // This method should not be called if scan is already in progress.
-        if (mScanning) throw new IllegalStateException("Scan is already in progress.");
-        // Neither should this method be called if the adapter is not available.
-        if (mBleScanner == null) throw new IllegalStateException("BLE is not available.");
 
         if (DEBUG) Log.i(TAG, "startScan()");
 
+        // This method should not be called if scan is already in progress.
+        if (mScanning) {
+            Slog.w(TAG, "Scan is already in progress.");
+            return;
+        }
+
+        // Neither should this method be called if the adapter is not available.
+        if (mBleScanner == null) {
+            Slog.w(TAG, "BLE is not available.");
+            return;
+        }
+
         // Collect MAC addresses from all associations.
         final Set<String> macAddresses = new HashSet<>();
         for (AssociationInfo association : mAssociationStore.getAssociations()) {
@@ -221,8 +229,18 @@
             filters.add(filter);
         }
 
-        mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback);
-        mScanning = true;
+        // BluetoothLeScanner will throw an IllegalStateException if startScan() is called while LE
+        // is not enabled.
+        if (mBtAdapter.isLeEnabled()) {
+            try {
+                mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback);
+                mScanning = true;
+            } catch (IllegalStateException e) {
+                Slog.w(TAG, "Exception while starting BLE scanning", e);
+            }
+        } else {
+            Slog.w(TAG, "BLE scanning is not turned on");
+        }
     }
 
     private void stopScanIfNeeded() {
@@ -240,11 +258,11 @@
         if (mBtAdapter.isLeEnabled()) {
             try {
                 mBleScanner.stopScan(mScanCallback);
-            } catch (RuntimeException e) {
-                // Just to be sure not to crash system server here if BluetoothLeScanner throws
-                // another RuntimeException.
+            } catch (IllegalStateException e) {
                 Slog.w(TAG, "Exception while stopping BLE scanning", e);
             }
+        } else {
+            Slog.w(TAG, "BLE scanning is not turned on");
         }
 
         mScanning = false;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index e9dd836..8d878af 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -1831,7 +1831,7 @@
         if (category != null && !dockAppStarted && (mStartDreamImmediatelyOnDock
                 || mWindowManager.isKeyguardShowingAndNotOccluded()
                 || !mPowerManager.isInteractive())) {
-            Sandman.startDreamWhenDockedIfAppropriate(getContext());
+            mInjector.startDreamWhenDockedIfAppropriate(getContext());
         }
     }
 
@@ -2145,5 +2145,9 @@
         public int getCallingUid() {
             return Binder.getCallingUid();
         }
+
+        public void startDreamWhenDockedIfAppropriate(Context context) {
+            Sandman.startDreamWhenDockedIfAppropriate(context);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 6b731c3..c128b5e 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -89,6 +89,7 @@
 import android.os.UserManager;
 import android.stats.devicepolicy.DevicePolicyEnums;
 import android.text.TextUtils;
+import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -3100,7 +3101,7 @@
                              */
                             if (!checkKeyIntent(
                                     Binder.getCallingUid(),
-                                    intent)) {
+                                    result)) {
                                 onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
                                         "invalid intent in bundle returned");
                                 return;
@@ -3519,7 +3520,7 @@
                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
                 if (!checkKeyIntent(
                         Binder.getCallingUid(),
-                        intent)) {
+                        result)) {
                     onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
                             "invalid intent in bundle returned");
                     return;
@@ -4870,7 +4871,13 @@
          * into launching arbitrary intents on the device via by tricking to click authenticator
          * supplied entries in the system Settings app.
          */
-         protected boolean checkKeyIntent(int authUid, Intent intent) {
+        protected boolean checkKeyIntent(int authUid, Bundle bundle) {
+            if (!checkKeyIntentParceledCorrectly(bundle)) {
+            	EventLog.writeEvent(0x534e4554, "250588548", authUid, "");
+                return false;
+            }
+
+            Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
             // Explicitly set an empty ClipData to ensure that we don't offer to
             // promote any Uris contained inside for granting purposes
             if (intent.getClipData() == null) {
@@ -4905,6 +4912,25 @@
             }
         }
 
+        /**
+         * Simulate the client side's deserialization of KEY_INTENT value, to make sure they don't
+         * violate our security policy.
+         *
+         * In particular we want to make sure the Authenticator doesn't trick users
+         * into launching arbitrary intents on the device via exploiting any other Parcel read/write
+         * mismatch problems.
+         */
+        private boolean checkKeyIntentParceledCorrectly(Bundle bundle) {
+            Parcel p = Parcel.obtain();
+            p.writeBundle(bundle);
+            p.setDataPosition(0);
+            Bundle simulateBundle = p.readBundle();
+            p.recycle();
+            Intent intent = bundle.getParcelable(AccountManager.KEY_INTENT, Intent.class);
+            return (intent.filterEquals(simulateBundle.getParcelable(AccountManager.KEY_INTENT,
+                Intent.class)));
+        }
+
         private boolean isExportedSystemActivity(ActivityInfo activityInfo) {
             String className = activityInfo.name;
             return "android".equals(activityInfo.packageName) &&
@@ -5051,7 +5077,7 @@
                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
                 if (!checkKeyIntent(
                         Binder.getCallingUid(),
-                        intent)) {
+                        result)) {
                     onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
                             "invalid intent in bundle returned");
                     return;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 9840e0f..9669c06 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4219,7 +4219,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) {
@@ -4323,6 +4324,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--) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d4b760f..df5113b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5008,7 +5008,8 @@
                 hostingRecord.getType(),
                 hostingRecord.getName(),
                 shortAction,
-                HostingRecord.getHostingTypeIdStatsd(hostingRecord.getType()));
+                HostingRecord.getHostingTypeIdStatsd(hostingRecord.getType()),
+                HostingRecord.getTriggerTypeForStatsd(hostingRecord.getTriggerType()));
         return true;
     }
 
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 606a09c..207c10c 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -36,6 +36,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;
@@ -2282,6 +2283,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:");
@@ -2325,6 +2330,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) {
@@ -2478,6 +2508,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/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 5856949..c235e05 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -519,7 +519,7 @@
             final Object curReceiver = r.receivers.get(curIndex);
             FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, r.curApp.uid,
                     r.callingUid == -1 ? Process.SYSTEM_UID : r.callingUid,
-                    ActivityManagerService.getShortAction(r.intent.getAction()),
+                    r.intent.getAction(),
                     curReceiver instanceof BroadcastFilter
                     ? BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME
                     : BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
@@ -692,7 +692,7 @@
             FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED,
                     receiverUid == -1 ? Process.SYSTEM_UID : receiverUid,
                     callingUid == -1 ? Process.SYSTEM_UID : callingUid,
-                    ActivityManagerService.getShortAction(intent.getAction()),
+                    intent.getAction(),
                     BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME,
                     BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM,
                     dispatchDelay, receiveDelay, 0 /* finish_delay */);
@@ -1921,7 +1921,7 @@
                 info.activityInfo.applicationInfo, true,
                 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                 new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST, r.curComponent,
-                        r.intent.getAction()),
+                        r.intent.getAction(), getHostingRecordTriggerType(r)),
                 isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
                 (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
         if (r.curApp == null) {
@@ -1944,6 +1944,16 @@
         mPendingBroadcastRecvIndex = recIdx;
     }
 
+    private String getHostingRecordTriggerType(BroadcastRecord r) {
+        if (r.alarm) {
+            return HostingRecord.TRIGGER_TYPE_ALARM;
+        } else if (r.pushMessage) {
+            return HostingRecord.TRIGGER_TYPE_PUSH_MESSAGE;
+        } else if (r.pushMessageOverQuota) {
+            return HostingRecord.TRIGGER_TYPE_PUSH_MESSAGE_OVER_QUOTA;
+        }
+        return HostingRecord.TRIGGER_TYPE_UNKNOWN;
+    }
 
     @Nullable
     private String getTargetPackage(BroadcastRecord r) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index ce4528b..baaae1d 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -71,6 +71,8 @@
     final boolean ordered;  // serialize the send to receivers?
     final boolean sticky;   // originated from existing sticky data?
     final boolean alarm;    // originated from an alarm triggering?
+    final boolean pushMessage; // originated from a push message?
+    final boolean pushMessageOverQuota; // originated from a push message which was over quota?
     final boolean initialSticky; // initial broadcast from register to sticky?
     final int userId;       // user id this broadcast was for
     final String resolvedType; // the resolved data type
@@ -309,6 +311,8 @@
         mBackgroundActivityStartsToken = backgroundActivityStartsToken;
         this.timeoutExempt = timeoutExempt;
         alarm = options != null && options.isAlarmBroadcast();
+        pushMessage = options != null && options.isPushMessagingBroadcast();
+        pushMessageOverQuota = options != null && options.isPushMessagingOverQuotaBroadcast();
     }
 
     /**
@@ -362,6 +366,8 @@
         mBackgroundActivityStartsToken = from.mBackgroundActivityStartsToken;
         timeoutExempt = from.timeoutExempt;
         alarm = from.alarm;
+        pushMessage = from.pushMessage;
+        pushMessageOverQuota = from.pushMessageOverQuota;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/HostingRecord.java b/services/core/java/com/android/server/am/HostingRecord.java
index f88a8ce..30811a1 100644
--- a/services/core/java/com/android/server/am/HostingRecord.java
+++ b/services/core/java/com/android/server/am/HostingRecord.java
@@ -16,10 +16,30 @@
 
 package com.android.server.am;
 
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_ACTIVITY;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_ADDED_APPLICATION;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_BACKUP;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_BROADCAST;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_CONTENT_PROVIDER;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_EMPTY;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_LINK_FAIL;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_NEXT_ACTIVITY;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_NEXT_TOP_ACTIVITY;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_ON_HOLD;
+import static com.android.internal.util.FrameworkStatsLog.PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_RESTART;
+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_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;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
-import android.os.ProcessStartTime;
 
 /**
  * This class describes various information required to start a process.
@@ -32,6 +52,9 @@
  *
  * The {@code mHostingZygote} field describes from which Zygote the new process should be spawned.
  *
+ * The {@code mTriggerType} field describes the trigger that started this processs. This could be
+ * an alarm or a push-message for a broadcast, for example. This is purely for logging and stats.
+ *
  * {@code mDefiningPackageName} contains the packageName of the package that defines the
  * component we want to start; this can be different from the packageName and uid in the
  * ApplicationInfo that we're creating the process with, in case the service is a
@@ -71,7 +94,13 @@
     public static final String HOSTING_TYPE_TOP_ACTIVITY = "top-activity";
     public static final String HOSTING_TYPE_EMPTY = "";
 
-    private @NonNull final String mHostingType;
+    public static final String TRIGGER_TYPE_UNKNOWN = "unknown";
+    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;
     private final int mHostingZygote;
     private final String mDefiningPackageName;
@@ -79,11 +108,12 @@
     private final boolean mIsTopApp;
     private final String mDefiningProcessName;
     @Nullable private final String mAction;
+    @NonNull private final String mTriggerType;
 
     public HostingRecord(@NonNull String hostingType) {
         this(hostingType, null /* hostingName */, REGULAR_ZYGOTE, null /* definingPackageName */,
                 -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */,
-                null /* action */);
+                null /* action */, TRIGGER_TYPE_UNKNOWN);
     }
 
     public HostingRecord(@NonNull String hostingType, ComponentName hostingName) {
@@ -91,22 +121,24 @@
     }
 
     public HostingRecord(@NonNull String hostingType, ComponentName hostingName,
-            @Nullable String action) {
+            @Nullable String action, @Nullable String triggerType) {
         this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE,
                 null /* definingPackageName */, -1 /* mDefiningUid */, false /* isTopApp */,
-                null /* definingProcessName */, action);
+                null /* definingProcessName */, action, triggerType);
     }
 
     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 */);
+                definingUid, false /* isTopApp */, definingProcessName, null /* action */,
+                triggerType);
     }
 
     public HostingRecord(@NonNull String hostingType, ComponentName hostingName, boolean isTopApp) {
         this(hostingType, hostingName.toShortString(), REGULAR_ZYGOTE,
                 null /* definingPackageName */, -1 /* mDefiningUid */, isTopApp /* isTopApp */,
-                null /* definingProcessName */, null /* action */);
+                null /* definingProcessName */, null /* action */, TRIGGER_TYPE_UNKNOWN);
     }
 
     public HostingRecord(@NonNull String hostingType, String hostingName) {
@@ -121,12 +153,12 @@
     private HostingRecord(@NonNull String hostingType, String hostingName, int hostingZygote) {
         this(hostingType, hostingName, hostingZygote, null /* definingPackageName */,
                 -1 /* mDefiningUid */, false /* isTopApp */, null /* definingProcessName */,
-                null /* action */);
+                null /* action */, TRIGGER_TYPE_UNKNOWN);
     }
 
     private HostingRecord(@NonNull String hostingType, String hostingName, int hostingZygote,
             String definingPackageName, int definingUid, boolean isTopApp,
-            String definingProcessName, @Nullable String action) {
+            String definingProcessName, @Nullable String action, String triggerType) {
         mHostingType = hostingType;
         mHostingName = hostingName;
         mHostingZygote = hostingZygote;
@@ -135,6 +167,7 @@
         mIsTopApp = isTopApp;
         mDefiningProcessName = definingProcessName;
         mAction = action;
+        mTriggerType = triggerType;
     }
 
     public @NonNull String getType() {
@@ -188,6 +221,11 @@
         return mAction;
     }
 
+    /** Returns the type of trigger that led to this process start. */
+    public @NonNull String getTriggerType() {
+        return mTriggerType;
+    }
+
     /**
      * Creates a HostingRecord for a process that must spawn from the webview zygote
      * @param hostingName name of the component to be hosted in this process
@@ -197,7 +235,7 @@
             String definingPackageName, int definingUid, String definingProcessName) {
         return new HostingRecord(HostingRecord.HOSTING_TYPE_EMPTY, hostingName.toShortString(),
                 WEBVIEW_ZYGOTE, definingPackageName, definingUid, false /* isTopApp */,
-                definingProcessName, null /* action */);
+                definingProcessName, null /* action */, TRIGGER_TYPE_UNKNOWN);
     }
 
     /**
@@ -211,7 +249,7 @@
             int definingUid, String definingProcessName) {
         return new HostingRecord(HostingRecord.HOSTING_TYPE_EMPTY, hostingName.toShortString(),
                 APP_ZYGOTE, definingPackageName, definingUid, false /* isTopApp */,
-                definingProcessName, null /* action */);
+                definingProcessName, null /* action */, TRIGGER_TYPE_UNKNOWN);
     }
 
     /**
@@ -236,35 +274,55 @@
     public static int getHostingTypeIdStatsd(@NonNull String hostingType) {
         switch(hostingType) {
             case HOSTING_TYPE_ACTIVITY:
-                return ProcessStartTime.HOSTING_TYPE_ACTIVITY;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_ACTIVITY;
             case HOSTING_TYPE_ADDED_APPLICATION:
-                return ProcessStartTime.HOSTING_TYPE_ADDED_APPLICATION;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_ADDED_APPLICATION;
             case HOSTING_TYPE_BACKUP:
-                return ProcessStartTime.HOSTING_TYPE_BACKUP;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_BACKUP;
             case HOSTING_TYPE_BROADCAST:
-                return ProcessStartTime.HOSTING_TYPE_BROADCAST;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_BROADCAST;
             case HOSTING_TYPE_CONTENT_PROVIDER:
-                return ProcessStartTime.HOSTING_TYPE_CONTENT_PROVIDER;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_CONTENT_PROVIDER;
             case HOSTING_TYPE_LINK_FAIL:
-                return ProcessStartTime.HOSTING_TYPE_LINK_FAIL;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_LINK_FAIL;
             case HOSTING_TYPE_ON_HOLD:
-                return ProcessStartTime.HOSTING_TYPE_ON_HOLD;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_ON_HOLD;
             case HOSTING_TYPE_NEXT_ACTIVITY:
-                return ProcessStartTime.HOSTING_TYPE_NEXT_ACTIVITY;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_NEXT_ACTIVITY;
             case HOSTING_TYPE_NEXT_TOP_ACTIVITY:
-                return ProcessStartTime.HOSTING_TYPE_NEXT_TOP_ACTIVITY;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_NEXT_TOP_ACTIVITY;
             case HOSTING_TYPE_RESTART:
-                return ProcessStartTime.HOSTING_TYPE_RESTART;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_RESTART;
             case HOSTING_TYPE_SERVICE:
-                return ProcessStartTime.HOSTING_TYPE_SERVICE;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_SERVICE;
             case HOSTING_TYPE_SYSTEM:
-                return ProcessStartTime.HOSTING_TYPE_SYSTEM;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_SYSTEM;
             case HOSTING_TYPE_TOP_ACTIVITY:
-                return ProcessStartTime.HOSTING_TYPE_TOP_ACTIVITY;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_TOP_ACTIVITY;
             case HOSTING_TYPE_EMPTY:
-                return ProcessStartTime.HOSTING_TYPE_EMPTY;
+                return PROCESS_START_TIME__HOSTING_TYPE_ID__HOSTING_TYPE_EMPTY;
             default:
-                return ProcessStartTime.HOSTING_TYPE_UNKNOWN;
+                return PROCESS_START_TIME__TYPE__UNKNOWN;
+        }
+    }
+
+    /**
+     * Map the string triggerType to enum TriggerType defined in ProcessStartTime proto.
+     * @param triggerType
+     * @return enum TriggerType defined in ProcessStartTime proto
+     */
+    public static int getTriggerTypeForStatsd(@NonNull String triggerType) {
+        switch(triggerType) {
+            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_TYPE_PUSH_MESSAGE;
+            case TRIGGER_TYPE_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/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 0d08db9..736914a 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1365,7 +1365,8 @@
                     break;
                 case MSG_II_SET_HEARING_AID_VOLUME:
                     synchronized (mDeviceStateLock) {
-                        mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2);
+                        mBtHelper.setHearingAidVolume(msg.arg1, msg.arg2,
+                                mDeviceInventory.isHearingAidConnected());
                     }
                     break;
                 case MSG_II_SET_LE_AUDIO_OUT_VOLUME: {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index ee0d79f..35da73e 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -377,7 +377,8 @@
                         makeLeAudioDeviceUnavailable(address, btInfo.mAudioSystemDevice);
                     } else if (switchToAvailable) {
                         makeLeAudioDeviceAvailable(address, BtHelper.getName(btInfo.mDevice),
-                                streamType, btInfo.mVolume, btInfo.mAudioSystemDevice,
+                                streamType, btInfo.mVolume == -1 ? -1 : btInfo.mVolume * 10,
+                                btInfo.mAudioSystemDevice,
                                 "onSetBtActiveDevice");
                     }
                     break;
@@ -1161,6 +1162,22 @@
                 .record();
     }
 
+    /**
+     * Returns whether a device of type DEVICE_OUT_HEARING_AID is connected.
+     * Visibility by APM plays no role
+     * @return true if a DEVICE_OUT_HEARING_AID is connected, false otherwise.
+     */
+    boolean isHearingAidConnected() {
+        synchronized (mDevicesLock) {
+            for (DeviceInfo di : mConnectedDevices.values()) {
+                if (di.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
     @GuardedBy("mDevicesLock")
     private void makeLeAudioDeviceAvailable(String address, String name, int streamType,
             int volumeIndex, int device, String eventSource) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0b6b890..745555c 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -41,10 +41,12 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.IUidObserver;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.role.RoleManager;
 import android.bluetooth.BluetoothAdapter;
@@ -1185,6 +1187,8 @@
         mSafeMediaVolumeIndex = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
 
+        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+
         mUseFixedVolume = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_useFixedVolume);
 
@@ -1202,7 +1206,7 @@
         mPlaybackMonitor =
                 new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM],
                         device -> onMuteAwaitConnectionTimeout(device));
-        mPlaybackMonitor.registerPlaybackCallback(mVoicePlaybackActivityMonitor, true);
+        mPlaybackMonitor.registerPlaybackCallback(mPlaybackActivityMonitor, true);
 
         mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
 
@@ -1308,6 +1312,7 @@
 
         intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
         intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
+        intentFilter.addAction(ACTION_CHECK_MUSIC_ACTIVE);
 
         mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null,
                 Context.RECEIVER_EXPORTED);
@@ -1927,13 +1932,7 @@
         if (state == AudioService.CONNECTION_STATE_CONNECTED) {
             // DEVICE_OUT_HDMI is now connected
             if (mSafeMediaVolumeDevices.contains(AudioSystem.DEVICE_OUT_HDMI)) {
-                sendMsg(mAudioHandler,
-                        MSG_CHECK_MUSIC_ACTIVE,
-                        SENDMSG_REPLACE,
-                        0,
-                        0,
-                        caller,
-                        MUSIC_ACTIVE_POLL_PERIOD_MS);
+                scheduleMusicActiveCheck();
             }
 
             if (isPlatformTelevision()) {
@@ -3822,8 +3821,9 @@
     }
 
     private AtomicBoolean mVoicePlaybackActive = new AtomicBoolean(false);
+    private AtomicBoolean mMediaPlaybackActive = new AtomicBoolean(false);
 
-    private final IPlaybackConfigDispatcher mVoicePlaybackActivityMonitor =
+    private final IPlaybackConfigDispatcher mPlaybackActivityMonitor =
             new IPlaybackConfigDispatcher.Stub() {
         @Override
         public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
@@ -3836,19 +3836,26 @@
 
     private void onPlaybackConfigChange(List<AudioPlaybackConfiguration> configs) {
         boolean voiceActive = false;
+        boolean mediaActive = false;
         for (AudioPlaybackConfiguration config : configs) {
             final int usage = config.getAudioAttributes().getUsage();
-            if ((usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
-                    || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
-                    && config.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+            if (!config.isActive()) {
+                continue;
+            }
+            if (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
+                    || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING) {
                 voiceActive = true;
-                break;
+            }
+            if (usage == AudioAttributes.USAGE_MEDIA || usage == AudioAttributes.USAGE_GAME) {
+                mediaActive = true;
             }
         }
         if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
             updateHearingAidVolumeOnVoiceActivityUpdate();
         }
-
+        if (mMediaPlaybackActive.getAndSet(mediaActive) != mediaActive && mediaActive) {
+            scheduleMusicActiveCheck();
+        }
         // Update playback active state for all apps in audio mode stack.
         // When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
         // and request an audio mode update immediately. Upon any other change, queue the message
@@ -4011,7 +4018,7 @@
         }
     }
 
-    private void setLeAudioVolumeOnModeUpdate(int mode) {
+    private void setLeAudioVolumeOnModeUpdate(int mode, int streamType, int device) {
         switch (mode) {
             case AudioSystem.MODE_IN_COMMUNICATION:
             case AudioSystem.MODE_IN_CALL:
@@ -4025,8 +4032,6 @@
                 return;
         }
 
-        int streamType = getBluetoothContextualVolumeStream(mode);
-
         // Currently, DEVICE_OUT_BLE_HEADSET is the only output type for LE_AUDIO profile.
         // (See AudioDeviceBroker#createBtDeviceInfo())
         int index = mStreamStates[streamType].getIndex(AudioSystem.DEVICE_OUT_BLE_HEADSET);
@@ -4037,6 +4042,7 @@
                     + index + " maxIndex=" + maxIndex + " streamType=" + streamType);
         }
         mDeviceBroker.postSetLeAudioVolumeIndex(index, maxIndex, streamType);
+        mDeviceBroker.postApplyVolumeOnDevice(streamType, device, "setLeAudioVolumeOnModeUpdate");
     }
 
     private void setStreamVolume(int streamType, int index, int flags,
@@ -5417,7 +5423,7 @@
 
                 // Forcefully set LE audio volume as a workaround, since the value of 'device'
                 // is not DEVICE_OUT_BLE_* even when BLE is connected.
-                setLeAudioVolumeOnModeUpdate(mode);
+                setLeAudioVolumeOnModeUpdate(mode, streamType, device);
 
                 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
                 // connections not started by the application changing the mode when pid changes
@@ -6032,30 +6038,52 @@
         return mContentResolver;
     }
 
+    private void scheduleMusicActiveCheck() {
+        synchronized (mSafeMediaVolumeStateLock) {
+            cancelMusicActiveCheck();
+            mMusicActiveIntent = PendingIntent.getBroadcast(mContext,
+                REQUEST_CODE_CHECK_MUSIC_ACTIVE,
+                new Intent(ACTION_CHECK_MUSIC_ACTIVE),
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    SystemClock.elapsedRealtime()
+                    + MUSIC_ACTIVE_POLL_PERIOD_MS, mMusicActiveIntent);
+        }
+    }
+
+    private void cancelMusicActiveCheck() {
+        synchronized (mSafeMediaVolumeStateLock) {
+            if (mMusicActiveIntent != null) {
+                mAlarmManager.cancel(mMusicActiveIntent);
+                mMusicActiveIntent = null;
+            }
+        }
+    }
     private void onCheckMusicActive(String caller) {
         synchronized (mSafeMediaVolumeStateLock) {
             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
                 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
-
-                if (mSafeMediaVolumeDevices.contains(device)) {
-                    sendMsg(mAudioHandler,
-                            MSG_CHECK_MUSIC_ACTIVE,
-                            SENDMSG_REPLACE,
-                            0,
-                            0,
-                            caller,
-                            MUSIC_ACTIVE_POLL_PERIOD_MS);
+                if (mSafeMediaVolumeDevices.contains(device)
+                        && mAudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
+                    scheduleMusicActiveCheck();
                     int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
-                    if (mAudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)
-                            && (index > safeMediaVolumeIndex(device))) {
+                    if (index > safeMediaVolumeIndex(device)) {
                         // Approximate cumulative active music time
-                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
+                        long curTimeMs = SystemClock.elapsedRealtime();
+                        if (mLastMusicActiveTimeMs != 0) {
+                            mMusicActiveMs += (int) (curTimeMs - mLastMusicActiveTimeMs);
+                        }
+                        mLastMusicActiveTimeMs = curTimeMs;
+                        Log.i(TAG, "onCheckMusicActive() mMusicActiveMs: " + mMusicActiveMs);
                         if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
                             setSafeMediaVolumeEnabled(true, caller);
                             mMusicActiveMs = 0;
                         }
                         saveMusicActiveMs();
                     }
+                } else {
+                    cancelMusicActiveCheck();
+                    mLastMusicActiveTimeMs = 0;
                 }
             }
         }
@@ -6124,6 +6152,7 @@
                         } else {
                             // We have existing playback time recorded, already confirmed.
                             mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
+                            mLastMusicActiveTimeMs = 0;
                         }
                     }
                 } else {
@@ -8633,13 +8662,7 @@
     @VisibleForTesting
     public void checkMusicActive(int deviceType, String caller) {
         if (mSafeMediaVolumeDevices.contains(deviceType)) {
-            sendMsg(mAudioHandler,
-                    MSG_CHECK_MUSIC_ACTIVE,
-                    SENDMSG_REPLACE,
-                    0,
-                    0,
-                    caller,
-                    MUSIC_ACTIVE_POLL_PERIOD_MS);
+            scheduleMusicActiveCheck();
         }
     }
 
@@ -8764,6 +8787,8 @@
                                 suspendedPackages[i], suspendedUids[i]);
                     }
                 }
+            } else if (action.equals(ACTION_CHECK_MUSIC_ACTIVE)) {
+                onCheckMusicActive(ACTION_CHECK_MUSIC_ACTIVE);
             }
         }
     } // end class AudioServiceBroadcastReceiver
@@ -9709,12 +9734,20 @@
     // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
     // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
     private int mMusicActiveMs;
+    private long mLastMusicActiveTimeMs = 0;
+    private PendingIntent mMusicActiveIntent = null;
+    private AlarmManager mAlarmManager;
+
     private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
     private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
     private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
     // check playback or record activity every 6 seconds for UIDs owning mode IN_COMMUNICATION
     private static final int CHECK_MODE_FOR_UID_PERIOD_MS = 6000;
 
+    private static final String ACTION_CHECK_MUSIC_ACTIVE =
+            AudioService.class.getSimpleName() + ".CHECK_MUSIC_ACTIVE";
+    private static final int REQUEST_CODE_CHECK_MUSIC_ACTIVE = 1;
+
     private int safeMediaVolumeIndex(int device) {
         if (!mSafeMediaVolumeDevices.contains(device)) {
             return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
@@ -9736,14 +9769,9 @@
                 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
                     mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
                     mMusicActiveMs = 1;  // nonzero = confirmed
+                    mLastMusicActiveTimeMs = 0;
                     saveMusicActiveMs();
-                    sendMsg(mAudioHandler,
-                            MSG_CHECK_MUSIC_ACTIVE,
-                            SENDMSG_REPLACE,
-                            0,
-                            0,
-                            caller,
-                            MUSIC_ACTIVE_POLL_PERIOD_MS);
+                    scheduleMusicActiveCheck();
                 }
             }
         }
@@ -9785,7 +9813,9 @@
     public void disableSafeMediaVolume(String callingPackage) {
         enforceVolumeController("disable the safe media volume");
         synchronized (mSafeMediaVolumeStateLock) {
+            final long identity = Binder.clearCallingIdentity();
             setSafeMediaVolumeEnabled(false, callingPackage);
+            Binder.restoreCallingIdentity(identity);
             if (mPendingVolumeCommand != null) {
                 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
                                   mPendingVolumeCommand.mIndex,
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index d0f5470..6cd42f8 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -424,7 +424,8 @@
         mLeAudio.setVolume(volume);
     }
 
-    /*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
+    /*package*/ synchronized void setHearingAidVolume(int index, int streamType,
+            boolean isHeadAidConnected) {
         if (mHearingAid == null) {
             if (AudioService.DEBUG_VOL) {
                 Log.i(TAG, "setHearingAidVolume: null mHearingAid");
@@ -441,8 +442,11 @@
             Log.i(TAG, "setHearingAidVolume: calling mHearingAid.setVolume idx="
                     + index + " gain=" + gainDB);
         }
-        AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
-                AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
+        // do not log when hearing aid is not connected to avoid confusion when reading dumpsys
+        if (isHeadAidConnected) {
+            AudioService.sVolumeLogger.log(new AudioServiceEvents.VolumeEvent(
+                    AudioServiceEvents.VolumeEvent.VOL_SET_HEARING_AID_VOL, index, gainDB));
+        }
         mHearingAid.setVolume(gainDB);
     }
 
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index a7d3729..40e28da 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -592,10 +592,14 @@
         }
 
         pw.println();
+        pw.println("  mAmbientBrightnessThresholds=");
         mAmbientBrightnessThresholds.dump(pw);
+        pw.println("  mScreenBrightnessThresholds=");
         mScreenBrightnessThresholds.dump(pw);
+        pw.println("  mScreenBrightnessThresholdsIdle=");
         mScreenBrightnessThresholdsIdle.dump(pw);
-        mScreenBrightnessThresholdsIdle.dump(pw);
+        pw.println("  mAmbientBrightnessThresholdsIdle=");
+        mAmbientBrightnessThresholdsIdle.dump(pw);
     }
 
     private String configStateToString(int state) {
@@ -860,6 +864,7 @@
                 Slog.d(TAG, "updateAmbientLux: "
                         + ((mFastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": "
                         + "mBrighteningLuxThreshold=" + mAmbientBrighteningThreshold + ", "
+                        + "mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold + ", "
                         + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", "
                         + "mAmbientLux=" + mAmbientLux);
             }
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 4165186..1ae37bb 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -27,6 +27,7 @@
 import android.os.PowerManager;
 import android.text.TextUtils;
 import android.util.MathUtils;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.Spline;
 import android.view.DisplayAddress;
@@ -51,7 +52,7 @@
 import com.android.server.display.config.SensorDetails;
 import com.android.server.display.config.ThermalStatus;
 import com.android.server.display.config.ThermalThrottling;
-import com.android.server.display.config.Thresholds;
+import com.android.server.display.config.ThresholdPoint;
 import com.android.server.display.config.XmlParser;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -188,42 +189,153 @@
  *      <ambientLightHorizonLong>10001</ambientLightHorizonLong>
  *      <ambientLightHorizonShort>2001</ambientLightHorizonShort>
  *
- *      <displayBrightnessChangeThresholds> // Thresholds for screen changes
- *        <brighteningThresholds>     // Thresholds for active mode brightness changes.
- *          <minimum>0.001</minimum>  // Minimum change needed in screen brightness to brighten.
- *        </brighteningThresholds>
- *        <darkeningThresholds>
- *          <minimum>0.002</minimum>  // Minimum change needed in screen brightness to darken.
- *        </darkeningThresholds>
- *      </displayBrightnessChangeThresholds>
- *
- *      <ambientBrightnessChangeThresholds> // Thresholds for lux changes
- *        <brighteningThresholds>     // Thresholds for active mode brightness changes.
- *          <minimum>0.003</minimum>  // Minimum change needed in ambient brightness to brighten.
- *        </brighteningThresholds>
- *        <darkeningThresholds>
- *          <minimum>0.004</minimum>  // Minimum change needed in ambient brightness to darken.
- *        </darkeningThresholds>
- *      </ambientBrightnessChangeThresholds>
- *
- *      <displayBrightnessChangeThresholdsIdle> // Thresholds for screen changes in idle mode
- *        <brighteningThresholds>     // Thresholds for idle mode brightness changes.
- *          <minimum>0.001</minimum>  // Minimum change needed in screen brightness to brighten.
- *        </brighteningThresholds>
- *        <darkeningThresholds>
- *          <minimum>0.002</minimum>  // Minimum change needed in screen brightness to darken.
- *        </darkeningThresholds>
- *      </displayBrightnessChangeThresholdsIdle>
- *
- *      <ambientBrightnessChangeThresholdsIdle> // Thresholds for lux changes in idle mode
- *        <brighteningThresholds>     // Thresholds for idle mode brightness changes.
- *          <minimum>0.003</minimum>  // Minimum change needed in ambient brightness to brighten.
- *        </brighteningThresholds>
- *        <darkeningThresholds>
- *          <minimum>0.004</minimum>  // Minimum change needed in ambient brightness to darken.
- *        </darkeningThresholds>
- *      </ambientBrightnessChangeThresholdsIdle>
- *
+ *     <ambientBrightnessChangeThresholds>  // Thresholds for lux changes
+ *         <brighteningThresholds>
+ *             // Minimum change needed in ambient brightness to brighten screen.
+ *             <minimum>10</minimum>
+ *             // Percentage increase of lux needed to increase the screen brightness at a lux range
+ *             // above the specified threshold.
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>13</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>100</threshold><percentage>14</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>200</threshold><percentage>15</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </brighteningThresholds>
+ *         <darkeningThresholds>
+*             // Minimum change needed in ambient brightness to darken screen.
+ *             <minimum>30</minimum>
+ *             // Percentage increase of lux needed to decrease the screen brightness at a lux range
+ *             // above the specified threshold.
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>15</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>300</threshold><percentage>16</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>400</threshold><percentage>17</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </darkeningThresholds>
+ *     </ambientBrightnessChangeThresholds>
+ *     <displayBrightnessChangeThresholds>   // Thresholds for screen brightness changes
+ *         <brighteningThresholds>
+ *             // Minimum change needed in screen brightness to brighten screen.
+ *             <minimum>0.1</minimum>
+ *             // Percentage increase of screen brightness needed to increase the screen brightness
+ *             // at a lux range above the specified threshold.
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold>
+ *                     <percentage>9</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.10</threshold>
+ *                     <percentage>10</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.20</threshold>
+ *                     <percentage>11</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </brighteningThresholds>
+ *         <darkeningThresholds>
+ *             // Minimum change needed in screen brightness to darken screen.
+ *             <minimum>0.3</minimum>
+ *             // Percentage increase of screen brightness needed to decrease the screen brightness
+ *             // at a lux range above the specified threshold.
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>11</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.11</threshold><percentage>12</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.21</threshold><percentage>13</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </darkeningThresholds>
+ *     </displayBrightnessChangeThresholds>
+ *     <ambientBrightnessChangeThresholdsIdle>   // Thresholds for lux changes in idle mode
+ *         <brighteningThresholds>
+ *             // Minimum change needed in ambient brightness to brighten screen in idle mode
+ *             <minimum>20</minimum>
+ *             // Percentage increase of lux needed to increase the screen brightness at a lux range
+ *             // above the specified threshold whilst in idle mode.
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>21</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>500</threshold><percentage>22</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>600</threshold><percentage>23</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </brighteningThresholds>
+ *         <darkeningThresholds>
+ *             // Minimum change needed in ambient brightness to darken screen in idle mode
+ *             <minimum>40</minimum>
+ *             // Percentage increase of lux needed to decrease the screen brightness at a lux range
+ *             // above the specified threshold whilst in idle mode.
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>23</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>700</threshold><percentage>24</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>800</threshold><percentage>25</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </darkeningThresholds>
+ *     </ambientBrightnessChangeThresholdsIdle>
+ *     <displayBrightnessChangeThresholdsIdle>    // Thresholds for idle screen brightness changes
+ *         <brighteningThresholds>
+ *             // Minimum change needed in screen brightness to brighten screen in idle mode
+ *             <minimum>0.2</minimum>
+ *             // Percentage increase of screen brightness needed to increase the screen brightness
+ *             // at a lux range above the specified threshold whilst in idle mode
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>17</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.12</threshold><percentage>18</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.22</threshold><percentage>19</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </brighteningThresholds>
+ *         <darkeningThresholds>
+ *             // Minimum change needed in screen brightness to darken screen in idle mode
+ *             <minimum>0.4</minimum>
+ *             // Percentage increase of screen brightness needed to decrease the screen brightness
+ *             // at a lux range above the specified threshold whilst in idle mode
+ *             <brightnessThresholdPoints>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0</threshold><percentage>19</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.13</threshold><percentage>20</percentage>
+ *                 </brightnessThresholdPoint>
+ *                 <brightnessThresholdPoint>
+ *                     <threshold>0.23</threshold><percentage>21</percentage>
+ *                 </brightnessThresholdPoint>
+ *             </brightnessThresholdPoints>
+ *         </darkeningThresholds>
+ *     </displayBrightnessChangeThresholdsIdle>
  *    </displayConfiguration>
  *  }
  *  </pre>
@@ -247,6 +359,13 @@
     private static final String NO_SUFFIX_FORMAT = "%d";
     private static final long STABLE_FLAG = 1L << 62;
 
+    private static final float[] DEFAULT_AMBIENT_THRESHOLD_LEVELS = new float[]{0f};
+    private static final float[] DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS = new float[]{100f};
+    private static final float[] DEFAULT_AMBIENT_DARKENING_THRESHOLDS = new float[]{200f};
+    private static final float[] DEFAULT_SCREEN_THRESHOLD_LEVELS = new float[]{0f};
+    private static final float[] DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS = new float[]{100f};
+    private static final float[] DEFAULT_SCREEN_DARKENING_THRESHOLDS = new float[]{200f};
+
     private static final int INTERPOLATION_DEFAULT = 0;
     private static final int INTERPOLATION_LINEAR = 1;
 
@@ -344,6 +463,31 @@
     private float mAmbientLuxBrighteningMinThresholdIdle = 0.0f;
     private float mAmbientLuxDarkeningMinThreshold = 0.0f;
     private float mAmbientLuxDarkeningMinThresholdIdle = 0.0f;
+
+    // Screen brightness thresholds levels & percentages
+    private float[] mScreenBrighteningLevels = DEFAULT_SCREEN_THRESHOLD_LEVELS;
+    private float[] mScreenBrighteningPercentages = DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS;
+    private float[] mScreenDarkeningLevels = DEFAULT_SCREEN_THRESHOLD_LEVELS;
+    private float[] mScreenDarkeningPercentages = DEFAULT_SCREEN_DARKENING_THRESHOLDS;
+
+    // Screen brightness thresholds levels & percentages for idle mode
+    private float[] mScreenBrighteningLevelsIdle = DEFAULT_SCREEN_THRESHOLD_LEVELS;
+    private float[] mScreenBrighteningPercentagesIdle = DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS;
+    private float[] mScreenDarkeningLevelsIdle = DEFAULT_SCREEN_THRESHOLD_LEVELS;
+    private float[] mScreenDarkeningPercentagesIdle = DEFAULT_SCREEN_DARKENING_THRESHOLDS;
+
+    // Ambient brightness thresholds levels & percentages
+    private float[] mAmbientBrighteningLevels = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
+    private float[] mAmbientBrighteningPercentages = DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS;
+    private float[] mAmbientDarkeningLevels = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
+    private float[] mAmbientDarkeningPercentages = DEFAULT_AMBIENT_DARKENING_THRESHOLDS;
+
+    // Ambient brightness thresholds levels & percentages for idle mode
+    private float[] mAmbientBrighteningLevelsIdle = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
+    private float[] mAmbientBrighteningPercentagesIdle = DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS;
+    private float[] mAmbientDarkeningLevelsIdle = DEFAULT_AMBIENT_THRESHOLD_LEVELS;
+    private float[] mAmbientDarkeningPercentagesIdle = DEFAULT_AMBIENT_DARKENING_THRESHOLDS;
+
     private Spline mBrightnessToBacklightSpline;
     private Spline mBacklightToBrightnessSpline;
     private Spline mBacklightToNitsSpline;
@@ -684,7 +828,7 @@
     /**
      * The minimum value for the ambient lux increase for a screen brightness change to actually
      * occur.
-     * @return float value in brightness scale of 0 - 1.
+     * @return float value in lux.
      */
     public float getAmbientLuxBrighteningMinThreshold() {
         return mAmbientLuxBrighteningMinThreshold;
@@ -693,7 +837,7 @@
     /**
      * The minimum value for the ambient lux decrease for a screen brightness change to actually
      * occur.
-     * @return float value in brightness scale of 0 - 1.
+     * @return float value in lux.
      */
     public float getAmbientLuxDarkeningMinThreshold() {
         return mAmbientLuxDarkeningMinThreshold;
@@ -702,7 +846,7 @@
     /**
      * The minimum value for the ambient lux increase for a screen brightness change to actually
      * occur while in idle screen brightness mode.
-     * @return float value in brightness scale of 0 - 1.
+     * @return float value in lux.
      */
     public float getAmbientLuxBrighteningMinThresholdIdle() {
         return mAmbientLuxBrighteningMinThresholdIdle;
@@ -711,12 +855,262 @@
     /**
      * The minimum value for the ambient lux decrease for a screen brightness change to actually
      * occur while in idle screen brightness mode.
-     * @return float value in brightness scale of 0 - 1.
+     * @return float value in lux.
      */
     public float getAmbientLuxDarkeningMinThresholdIdle() {
         return mAmbientLuxDarkeningMinThresholdIdle;
     }
 
+    /**
+     * The array that describes the range of screen brightness that each threshold percentage
+     * applies within.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current screen brightness value
+     * level = mScreenBrighteningLevels
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mScreenBrighteningPercentages[n]
+     * level[MAX] <= value             = mScreenBrighteningPercentages[MAX]
+     *
+     * @return the screen brightness levels between 0.0 and 1.0 for which each
+     * mScreenBrighteningPercentages applies
+     */
+    public float[] getScreenBrighteningLevels() {
+        return mScreenBrighteningLevels;
+    }
+
+    /**
+     * The array that describes the screen brightening threshold percentage change at each screen
+     * brightness level described in mScreenBrighteningLevels.
+     *
+     * @return the percentages between 0 and 100 of brightness increase required in order for the
+     * screen brightness to change
+     */
+    public float[] getScreenBrighteningPercentages() {
+        return mScreenBrighteningPercentages;
+    }
+
+    /**
+     * The array that describes the range of screen brightness that each threshold percentage
+     * applies within.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current screen brightness value
+     * level = mScreenDarkeningLevels
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mScreenDarkeningPercentages[n]
+     * level[MAX] <= value             = mScreenDarkeningPercentages[MAX]
+     *
+     * @return the screen brightness levels between 0.0 and 1.0 for which each
+     * mScreenDarkeningPercentages applies
+     */
+    public float[] getScreenDarkeningLevels() {
+        return mScreenDarkeningLevels;
+    }
+
+    /**
+     * The array that describes the screen darkening threshold percentage change at each screen
+     * brightness level described in mScreenDarkeningLevels.
+     *
+     * @return the percentages between 0 and 100 of brightness decrease required in order for the
+     * screen brightness to change
+     */
+    public float[] getScreenDarkeningPercentages() {
+        return mScreenDarkeningPercentages;
+    }
+
+    /**
+     * The array that describes the range of ambient brightness that each threshold
+     * percentage applies within.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current ambient brightness value
+     * level = mAmbientBrighteningLevels
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mAmbientBrighteningPercentages[n]
+     * level[MAX] <= value             = mAmbientBrighteningPercentages[MAX]
+     *
+     * @return the ambient brightness levels from 0 lux upwards for which each
+     * mAmbientBrighteningPercentages applies
+     */
+    public float[] getAmbientBrighteningLevels() {
+        return mAmbientBrighteningLevels;
+    }
+
+    /**
+     * The array that describes the ambient brightening threshold percentage change at each ambient
+     * brightness level described in mAmbientBrighteningLevels.
+     *
+     * @return the percentages between 0 and 100 of brightness increase required in order for the
+     * screen brightness to change
+     */
+    public float[] getAmbientBrighteningPercentages() {
+        return mAmbientBrighteningPercentages;
+    }
+
+    /**
+     * The array that describes the range of ambient brightness that each threshold percentage
+     * applies within.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current ambient brightness value
+     * level = mAmbientDarkeningLevels
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mAmbientDarkeningPercentages[n]
+     * level[MAX] <= value             = mAmbientDarkeningPercentages[MAX]
+     *
+     * @return the ambient brightness levels from 0 lux upwards for which each
+     * mAmbientDarkeningPercentages applies
+     */
+    public float[] getAmbientDarkeningLevels() {
+        return mAmbientDarkeningLevels;
+    }
+
+    /**
+     * The array that describes the ambient darkening threshold percentage change at each ambient
+     * brightness level described in mAmbientDarkeningLevels.
+     *
+     * @return the percentages between 0 and 100 of brightness decrease required in order for the
+     * screen brightness to change
+     */
+    public float[] getAmbientDarkeningPercentages() {
+        return mAmbientDarkeningPercentages;
+    }
+
+    /**
+     * The array that describes the range of screen brightness that each threshold percentage
+     * applies within whilst in idle screen brightness mode.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current screen brightness value
+     * level = mScreenBrighteningLevelsIdle
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mScreenBrighteningPercentagesIdle[n]
+     * level[MAX] <= value             = mScreenBrighteningPercentagesIdle[MAX]
+     *
+     * @return the screen brightness levels between 0.0 and 1.0 for which each
+     * mScreenBrighteningPercentagesIdle applies
+     */
+    public float[] getScreenBrighteningLevelsIdle() {
+        return mScreenBrighteningLevelsIdle;
+    }
+
+    /**
+     * The array that describes the screen brightening threshold percentage change at each screen
+     * brightness level described in mScreenBrighteningLevelsIdle.
+     *
+     * @return the percentages between 0 and 100 of brightness increase required in order for the
+     * screen brightness to change while in idle mode.
+     */
+    public float[] getScreenBrighteningPercentagesIdle() {
+        return mScreenBrighteningPercentagesIdle;
+    }
+
+    /**
+     * The array that describes the range of screen brightness that each threshold percentage
+     * applies within whilst in idle screen brightness mode.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current screen brightness value
+     * level = mScreenDarkeningLevelsIdle
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mScreenDarkeningPercentagesIdle[n]
+     * level[MAX] <= value             = mScreenDarkeningPercentagesIdle[MAX]
+     *
+     * @return the screen brightness levels between 0.0 and 1.0 for which each
+     * mScreenDarkeningPercentagesIdle applies
+     */
+    public float[] getScreenDarkeningLevelsIdle() {
+        return mScreenDarkeningLevelsIdle;
+    }
+
+    /**
+     * The array that describes the screen darkening threshold percentage change at each screen
+     * brightness level described in mScreenDarkeningLevelsIdle.
+     *
+     * @return the percentages between 0 and 100 of brightness decrease required in order for the
+     * screen brightness to change while in idle mode.
+     */
+    public float[] getScreenDarkeningPercentagesIdle() {
+        return mScreenDarkeningPercentagesIdle;
+    }
+
+    /**
+     * The array that describes the range of ambient brightness that each threshold percentage
+     * applies within whilst in idle screen brightness mode.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current ambient brightness value
+     * level = mAmbientBrighteningLevelsIdle
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mAmbientBrighteningPercentagesIdle[n]
+     * level[MAX] <= value             = mAmbientBrighteningPercentagesIdle[MAX]
+     *
+     * @return the ambient brightness levels from 0 lux upwards for which each
+     * mAmbientBrighteningPercentagesIdle applies
+     */
+    public float[] getAmbientBrighteningLevelsIdle() {
+        return mAmbientBrighteningLevelsIdle;
+    }
+
+    /**
+     * The array that describes the ambient brightness threshold percentage change whilst in
+     * idle screen brightness mode at each ambient brightness level described in
+     * mAmbientBrighteningLevelsIdle.
+     *
+     * @return the percentages between 0 and 100 of ambient brightness increase required in order
+     * for the screen brightness to change
+     */
+    public float[] getAmbientBrighteningPercentagesIdle() {
+        return mAmbientBrighteningPercentagesIdle;
+    }
+
+    /**
+     * The array that describes the range of ambient brightness that each threshold percentage
+     * applies within whilst in idle screen brightness mode.
+     *
+     * The (zero-based) index is calculated as follows
+     * value = current ambient brightness value
+     * level = mAmbientDarkeningLevelsIdle
+     *
+     * condition                       return
+     * value < level[0]                = 0.0f
+     * level[n] <= value < level[n+1]  = mAmbientDarkeningPercentagesIdle[n]
+     * level[MAX] <= value             = mAmbientDarkeningPercentagesIdle[MAX]
+     *
+     * @return the ambient brightness levels from 0 lux upwards for which each
+     * mAmbientDarkeningPercentagesIdle applies
+     */
+    public float[] getAmbientDarkeningLevelsIdle() {
+        return mAmbientDarkeningLevelsIdle;
+    }
+
+    /**
+     * The array that describes the ambient brightness threshold percentage change whilst in
+     * idle screen brightness mode at each ambient brightness level described in
+     * mAmbientDarkeningLevelsIdle.
+     *
+     * @return the percentages between 0 and 100 of ambient brightness decrease required in order
+     * for the screen brightness to change
+     */
+    public float[] getAmbientDarkeningPercentagesIdle() {
+        return mAmbientDarkeningPercentagesIdle;
+    }
+
     SensorData getAmbientLightSensor() {
         return mAmbientLightSensor;
     }
@@ -812,14 +1206,17 @@
                 + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
                 + ", mBrightnessThrottlingData=" + mBrightnessThrottlingData
                 + ", mOriginalBrightnessThrottlingData=" + mOriginalBrightnessThrottlingData
+                + "\n"
                 + ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
                 + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
                 + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
                 + ", mBrightnessRampDecreaseMaxMillis=" + mBrightnessRampDecreaseMaxMillis
                 + ", mBrightnessRampIncreaseMaxMillis=" + mBrightnessRampIncreaseMaxMillis
+                + "\n"
                 + ", mAmbientHorizonLong=" + mAmbientHorizonLong
                 + ", mAmbientHorizonShort=" + mAmbientHorizonShort
+                + "\n"
                 + ", mScreenDarkeningMinThreshold=" + mScreenDarkeningMinThreshold
                 + ", mScreenDarkeningMinThresholdIdle=" + mScreenDarkeningMinThresholdIdle
                 + ", mScreenBrighteningMinThreshold=" + mScreenBrighteningMinThreshold
@@ -829,6 +1226,41 @@
                 + ", mAmbientLuxBrighteningMinThreshold=" + mAmbientLuxBrighteningMinThreshold
                 + ", mAmbientLuxBrighteningMinThresholdIdle="
                 + mAmbientLuxBrighteningMinThresholdIdle
+                + "\n"
+                + ", mScreenBrighteningLevels=" + Arrays.toString(
+                mScreenBrighteningLevels)
+                + ", mScreenBrighteningPercentages=" + Arrays.toString(
+                mScreenBrighteningPercentages)
+                + ", mScreenDarkeningLevels=" + Arrays.toString(
+                mScreenDarkeningLevels)
+                + ", mScreenDarkeningPercentages=" + Arrays.toString(
+                mScreenDarkeningPercentages)
+                + ", mAmbientBrighteningLevels=" + Arrays.toString(
+                mAmbientBrighteningLevels)
+                + ", mAmbientBrighteningPercentages=" + Arrays.toString(
+                mAmbientBrighteningPercentages)
+                + ", mAmbientDarkeningLevels=" + Arrays.toString(
+                mAmbientDarkeningLevels)
+                + ", mAmbientDarkeningPercentages=" + Arrays.toString(
+                mAmbientDarkeningPercentages)
+                + "\n"
+                + ", mAmbientBrighteningLevelsIdle=" + Arrays.toString(
+                mAmbientBrighteningLevelsIdle)
+                + ", mAmbientBrighteningPercentagesIdle=" + Arrays.toString(
+                mAmbientBrighteningPercentagesIdle)
+                + ", mAmbientDarkeningLevelsIdle=" + Arrays.toString(
+                mAmbientDarkeningLevelsIdle)
+                + ", mAmbientDarkeningPercentagesIdle=" + Arrays.toString(
+                mAmbientDarkeningPercentagesIdle)
+                + ", mScreenBrighteningLevelsIdle=" + Arrays.toString(
+                mScreenBrighteningLevelsIdle)
+                + ", mScreenBrighteningPercentagesIdle=" + Arrays.toString(
+                mScreenBrighteningPercentagesIdle)
+                + ", mScreenDarkeningLevelsIdle=" + Arrays.toString(
+                mScreenDarkeningLevelsIdle)
+                + ", mScreenDarkeningPercentagesIdle=" + Arrays.toString(
+                mScreenDarkeningPercentagesIdle)
+                + "\n"
                 + ", mAmbientLightSensor=" + mAmbientLightSensor
                 + ", mProximitySensor=" + mProximitySensor
                 + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
@@ -914,6 +1346,7 @@
         loadBrightnessMapFromConfigXml();
         loadBrightnessRampsFromConfigXml();
         loadAmbientLightSensorFromConfigXml();
+        loadBrightnessChangeThresholdsFromXml();
         setProxSensorUnspecified();
         loadAutoBrightnessConfigsFromConfigXml();
         mLoadedFrom = "<config.xml>";
@@ -1454,91 +1887,287 @@
         }
     }
 
+    private void loadBrightnessChangeThresholdsFromXml() {
+        loadBrightnessChangeThresholds(/* config= */ null);
+    }
+
     private void loadBrightnessChangeThresholds(DisplayConfiguration config) {
-        Thresholds displayBrightnessThresholds = config.getDisplayBrightnessChangeThresholds();
-        Thresholds ambientBrightnessThresholds = config.getAmbientBrightnessChangeThresholds();
-        Thresholds displayBrightnessThresholdsIdle =
-                config.getDisplayBrightnessChangeThresholdsIdle();
-        Thresholds ambientBrightnessThresholdsIdle =
-                config.getAmbientBrightnessChangeThresholdsIdle();
-
-        loadDisplayBrightnessThresholds(displayBrightnessThresholds);
-        loadAmbientBrightnessThresholds(ambientBrightnessThresholds);
-        loadIdleDisplayBrightnessThresholds(displayBrightnessThresholdsIdle);
-        loadIdleAmbientBrightnessThresholds(ambientBrightnessThresholdsIdle);
+        loadDisplayBrightnessThresholds(config);
+        loadAmbientBrightnessThresholds(config);
+        loadDisplayBrightnessThresholdsIdle(config);
+        loadAmbientBrightnessThresholdsIdle(config);
     }
 
-    private void loadDisplayBrightnessThresholds(Thresholds displayBrightnessThresholds) {
-        if (displayBrightnessThresholds != null) {
-            BrightnessThresholds brighteningScreen =
-                    displayBrightnessThresholds.getBrighteningThresholds();
-            BrightnessThresholds darkeningScreen =
-                    displayBrightnessThresholds.getDarkeningThresholds();
+    private void loadDisplayBrightnessThresholds(DisplayConfiguration config) {
+        BrightnessThresholds brighteningScreen = null;
+        BrightnessThresholds darkeningScreen = null;
+        if (config != null && config.getDisplayBrightnessChangeThresholds() != null) {
+            brighteningScreen =
+                    config.getDisplayBrightnessChangeThresholds().getBrighteningThresholds();
+            darkeningScreen =
+                    config.getDisplayBrightnessChangeThresholds().getDarkeningThresholds();
 
-            if (brighteningScreen != null && brighteningScreen.getMinimum() != null) {
-                mScreenBrighteningMinThreshold = brighteningScreen.getMinimum().floatValue();
-            }
-            if (darkeningScreen != null && darkeningScreen.getMinimum() != null) {
-                mScreenDarkeningMinThreshold = darkeningScreen.getMinimum().floatValue();
-            }
+        }
+
+        // Screen bright/darkening threshold levels for active mode
+        Pair<float[], float[]> screenBrighteningPair = getBrightnessLevelAndPercentage(
+                brighteningScreen,
+                com.android.internal.R.array.config_screenThresholdLevels,
+                com.android.internal.R.array.config_screenBrighteningThresholds,
+                DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
+                /* potentialOldBrightnessScale= */ true);
+
+        mScreenBrighteningLevels = screenBrighteningPair.first;
+        mScreenBrighteningPercentages = screenBrighteningPair.second;
+
+        Pair<float[], float[]> screenDarkeningPair = getBrightnessLevelAndPercentage(
+                darkeningScreen,
+                com.android.internal.R.array.config_screenThresholdLevels,
+                com.android.internal.R.array.config_screenDarkeningThresholds,
+                DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_DARKENING_THRESHOLDS,
+                /* potentialOldBrightnessScale= */ true);
+        mScreenDarkeningLevels = screenDarkeningPair.first;
+        mScreenDarkeningPercentages = screenDarkeningPair.second;
+
+        // Screen bright/darkening threshold minimums for active mode
+        if (brighteningScreen != null && brighteningScreen.getMinimum() != null) {
+            mScreenBrighteningMinThreshold = brighteningScreen.getMinimum().floatValue();
+        }
+        if (darkeningScreen != null && darkeningScreen.getMinimum() != null) {
+            mScreenDarkeningMinThreshold = darkeningScreen.getMinimum().floatValue();
         }
     }
 
-    private void loadAmbientBrightnessThresholds(Thresholds ambientBrightnessThresholds) {
-        if (ambientBrightnessThresholds != null) {
-            BrightnessThresholds brighteningAmbientLux =
-                    ambientBrightnessThresholds.getBrighteningThresholds();
-            BrightnessThresholds darkeningAmbientLux =
-                    ambientBrightnessThresholds.getDarkeningThresholds();
+    private void loadAmbientBrightnessThresholds(DisplayConfiguration config) {
+        // Ambient Brightness Threshold Levels
+        BrightnessThresholds brighteningAmbientLux = null;
+        BrightnessThresholds darkeningAmbientLux = null;
+        if (config != null && config.getAmbientBrightnessChangeThresholds() != null) {
+            brighteningAmbientLux =
+                    config.getAmbientBrightnessChangeThresholds().getBrighteningThresholds();
+            darkeningAmbientLux =
+                    config.getAmbientBrightnessChangeThresholds().getDarkeningThresholds();
+        }
 
-            final BigDecimal ambientBrighteningThreshold = brighteningAmbientLux.getMinimum();
-            final BigDecimal ambientDarkeningThreshold = darkeningAmbientLux.getMinimum();
+        // Ambient bright/darkening threshold levels for active mode
+        Pair<float[], float[]> ambientBrighteningPair = getBrightnessLevelAndPercentage(
+                brighteningAmbientLux,
+                com.android.internal.R.array.config_ambientThresholdLevels,
+                com.android.internal.R.array.config_ambientBrighteningThresholds,
+                DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS);
+        mAmbientBrighteningLevels = ambientBrighteningPair.first;
+        mAmbientBrighteningPercentages = ambientBrighteningPair.second;
 
-            if (ambientBrighteningThreshold != null) {
-                mAmbientLuxBrighteningMinThreshold = ambientBrighteningThreshold.floatValue();
-            }
-            if (ambientDarkeningThreshold != null) {
-                mAmbientLuxDarkeningMinThreshold = ambientDarkeningThreshold.floatValue();
-            }
+        Pair<float[], float[]> ambientDarkeningPair = getBrightnessLevelAndPercentage(
+                darkeningAmbientLux,
+                com.android.internal.R.array.config_ambientThresholdLevels,
+                com.android.internal.R.array.config_ambientDarkeningThresholds,
+                DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_DARKENING_THRESHOLDS);
+        mAmbientDarkeningLevels = ambientDarkeningPair.first;
+        mAmbientDarkeningPercentages = ambientDarkeningPair.second;
+
+        // Ambient bright/darkening threshold minimums for active/idle mode
+        if (brighteningAmbientLux != null && brighteningAmbientLux.getMinimum() != null) {
+            mAmbientLuxBrighteningMinThreshold =
+                    brighteningAmbientLux.getMinimum().floatValue();
+        }
+
+        if (darkeningAmbientLux != null && darkeningAmbientLux.getMinimum() != null) {
+            mAmbientLuxDarkeningMinThreshold = darkeningAmbientLux.getMinimum().floatValue();
         }
     }
 
-    private void loadIdleDisplayBrightnessThresholds(Thresholds idleDisplayBrightnessThresholds) {
-        if (idleDisplayBrightnessThresholds != null) {
-            BrightnessThresholds brighteningScreenIdle =
-                    idleDisplayBrightnessThresholds.getBrighteningThresholds();
-            BrightnessThresholds darkeningScreenIdle =
-                    idleDisplayBrightnessThresholds.getDarkeningThresholds();
+    private void loadDisplayBrightnessThresholdsIdle(DisplayConfiguration config) {
+        BrightnessThresholds brighteningScreenIdle = null;
+        BrightnessThresholds darkeningScreenIdle = null;
+        if (config != null && config.getDisplayBrightnessChangeThresholdsIdle() != null) {
+            brighteningScreenIdle =
+                    config.getDisplayBrightnessChangeThresholdsIdle().getBrighteningThresholds();
+            darkeningScreenIdle =
+                    config.getDisplayBrightnessChangeThresholdsIdle().getDarkeningThresholds();
+        }
 
-            if (brighteningScreenIdle != null
-                    && brighteningScreenIdle.getMinimum() != null) {
-                mScreenBrighteningMinThresholdIdle =
-                        brighteningScreenIdle.getMinimum().floatValue();
-            }
-            if (darkeningScreenIdle != null && darkeningScreenIdle.getMinimum() != null) {
-                mScreenDarkeningMinThresholdIdle =
-                        darkeningScreenIdle.getMinimum().floatValue();
-            }
+        Pair<float[], float[]> screenBrighteningPair = getBrightnessLevelAndPercentage(
+                brighteningScreenIdle,
+                com.android.internal.R.array.config_screenThresholdLevels,
+                com.android.internal.R.array.config_screenBrighteningThresholds,
+                DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_BRIGHTENING_THRESHOLDS,
+                /* potentialOldBrightnessScale= */ true);
+        mScreenBrighteningLevelsIdle = screenBrighteningPair.first;
+        mScreenBrighteningPercentagesIdle = screenBrighteningPair.second;
+
+        Pair<float[], float[]> screenDarkeningPair = getBrightnessLevelAndPercentage(
+                darkeningScreenIdle,
+                com.android.internal.R.array.config_screenThresholdLevels,
+                com.android.internal.R.array.config_screenDarkeningThresholds,
+                DEFAULT_SCREEN_THRESHOLD_LEVELS, DEFAULT_SCREEN_DARKENING_THRESHOLDS,
+                /* potentialOldBrightnessScale= */ true);
+        mScreenDarkeningLevelsIdle = screenDarkeningPair.first;
+        mScreenDarkeningPercentagesIdle = screenDarkeningPair.second;
+
+        if (brighteningScreenIdle != null
+                && brighteningScreenIdle.getMinimum() != null) {
+            mScreenBrighteningMinThresholdIdle =
+                    brighteningScreenIdle.getMinimum().floatValue();
+        }
+        if (darkeningScreenIdle != null && darkeningScreenIdle.getMinimum() != null) {
+            mScreenDarkeningMinThresholdIdle =
+                    darkeningScreenIdle.getMinimum().floatValue();
         }
     }
 
-    private void loadIdleAmbientBrightnessThresholds(Thresholds idleAmbientBrightnessThresholds) {
-        if (idleAmbientBrightnessThresholds != null) {
-            BrightnessThresholds brighteningAmbientLuxIdle =
-                    idleAmbientBrightnessThresholds.getBrighteningThresholds();
-            BrightnessThresholds darkeningAmbientLuxIdle =
-                    idleAmbientBrightnessThresholds.getDarkeningThresholds();
+    private void loadAmbientBrightnessThresholdsIdle(DisplayConfiguration config) {
+        BrightnessThresholds brighteningAmbientLuxIdle = null;
+        BrightnessThresholds darkeningAmbientLuxIdle = null;
+        if (config != null && config.getAmbientBrightnessChangeThresholdsIdle() != null) {
+            brighteningAmbientLuxIdle =
+                    config.getAmbientBrightnessChangeThresholdsIdle().getBrighteningThresholds();
+            darkeningAmbientLuxIdle =
+                    config.getAmbientBrightnessChangeThresholdsIdle().getDarkeningThresholds();
+        }
 
-            if (brighteningAmbientLuxIdle != null
-                    && brighteningAmbientLuxIdle.getMinimum() != null) {
-                mAmbientLuxBrighteningMinThresholdIdle =
-                        brighteningAmbientLuxIdle.getMinimum().floatValue();
+        Pair<float[], float[]> ambientBrighteningPair = getBrightnessLevelAndPercentage(
+                brighteningAmbientLuxIdle,
+                com.android.internal.R.array.config_ambientThresholdLevels,
+                com.android.internal.R.array.config_ambientBrighteningThresholds,
+                DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_BRIGHTENING_THRESHOLDS);
+        mAmbientBrighteningLevelsIdle = ambientBrighteningPair.first;
+        mAmbientBrighteningPercentagesIdle = ambientBrighteningPair.second;
+
+        Pair<float[], float[]> ambientDarkeningPair = getBrightnessLevelAndPercentage(
+                darkeningAmbientLuxIdle,
+                com.android.internal.R.array.config_ambientThresholdLevels,
+                com.android.internal.R.array.config_ambientDarkeningThresholds,
+                DEFAULT_AMBIENT_THRESHOLD_LEVELS, DEFAULT_AMBIENT_DARKENING_THRESHOLDS);
+        mAmbientDarkeningLevelsIdle = ambientDarkeningPair.first;
+        mAmbientDarkeningPercentagesIdle = ambientDarkeningPair.second;
+
+        if (brighteningAmbientLuxIdle != null
+                && brighteningAmbientLuxIdle.getMinimum() != null) {
+            mAmbientLuxBrighteningMinThresholdIdle =
+                    brighteningAmbientLuxIdle.getMinimum().floatValue();
+        }
+
+        if (darkeningAmbientLuxIdle != null && darkeningAmbientLuxIdle.getMinimum() != null) {
+            mAmbientLuxDarkeningMinThresholdIdle =
+                    darkeningAmbientLuxIdle.getMinimum().floatValue();
+        }
+    }
+
+    private Pair<float[], float[]> getBrightnessLevelAndPercentage(BrightnessThresholds thresholds,
+            int configFallbackThreshold, int configFallbackPercentage, float[] defaultLevels,
+            float[] defaultPercentage) {
+        return getBrightnessLevelAndPercentage(thresholds, configFallbackThreshold,
+                configFallbackPercentage, defaultLevels, defaultPercentage, false);
+    }
+
+    // Returns two float arrays, one of the brightness levels and one of the corresponding threshold
+    // percentages for brightness levels at or above the lux value.
+    // Historically, config.xml would have an array for brightness levels that was 1 shorter than
+    // the levels array. Now we prepend a 0 to this array so they can be treated the same in the
+    // rest of the framework. Values were also defined in different units (permille vs percent).
+    private Pair<float[], float[]> getBrightnessLevelAndPercentage(BrightnessThresholds thresholds,
+            int configFallbackThreshold, int configFallbackPermille,
+            float[] defaultLevels, float[] defaultPercentage,
+            boolean potentialOldBrightnessScale) {
+        if (thresholds != null
+                && thresholds.getBrightnessThresholdPoints() != null
+                && thresholds.getBrightnessThresholdPoints()
+                .getBrightnessThresholdPoint().size() != 0) {
+
+            // The level and percentages arrays are equal length in the ddc (new system)
+            List<ThresholdPoint> points =
+                    thresholds.getBrightnessThresholdPoints().getBrightnessThresholdPoint();
+            final int size = points.size();
+
+            float[] thresholdLevels = new float[size];
+            float[] thresholdPercentages = new float[size];
+
+            int i = 0;
+            for (ThresholdPoint point : points) {
+                thresholdLevels[i] = point.getThreshold().floatValue();
+                thresholdPercentages[i] = point.getPercentage().floatValue();
+                i++;
             }
-            if (darkeningAmbientLuxIdle != null && darkeningAmbientLuxIdle.getMinimum() != null) {
-                mAmbientLuxDarkeningMinThresholdIdle =
-                        darkeningAmbientLuxIdle.getMinimum().floatValue();
+            return new Pair<>(thresholdLevels, thresholdPercentages);
+        } else {
+            // The level and percentages arrays are unequal length in config.xml (old system)
+            // We prefix the array with a 0 value to ensure they can be handled consistently
+            // with the new system.
+
+            // Load levels array
+            int[] configThresholdArray = mContext.getResources().getIntArray(
+                    configFallbackThreshold);
+            int configThresholdsSize;
+            if (configThresholdArray == null || configThresholdArray.length == 0) {
+                configThresholdsSize = 1;
+            } else {
+                configThresholdsSize = configThresholdArray.length + 1;
+            }
+
+
+            // Load percentage array
+            int[] configPermille = mContext.getResources().getIntArray(
+                    configFallbackPermille);
+
+            // Ensure lengths match up
+            boolean emptyArray = configPermille == null || configPermille.length == 0;
+            if (emptyArray && configThresholdsSize == 1) {
+                return new Pair<>(defaultLevels, defaultPercentage);
+            }
+            if (emptyArray || configPermille.length != configThresholdsSize) {
+                throw new IllegalArgumentException(
+                        "Brightness threshold arrays do not align in length");
+            }
+
+            // Calculate levels array
+            float[] configThresholdWithZeroPrefixed = new float[configThresholdsSize];
+            // Start at 1, so that 0 index value is 0.0f (default)
+            for (int i = 1; i < configThresholdsSize; i++) {
+                configThresholdWithZeroPrefixed[i] = (float) configThresholdArray[i - 1];
+            }
+            if (potentialOldBrightnessScale) {
+                configThresholdWithZeroPrefixed =
+                        constraintInRangeIfNeeded(configThresholdWithZeroPrefixed);
+            }
+
+            // Calculate percentages array
+            float[] configPercentage = new float[configThresholdsSize];
+            for (int i = 0; i < configPermille.length; i++) {
+                configPercentage[i] = configPermille[i] / 10.0f;
+            }
+            return new Pair<>(configThresholdWithZeroPrefixed, configPercentage);
+        }
+    }
+
+    /**
+     * This check is due to historical reasons, where screen thresholdLevels used to be
+     * integer values in the range of [0-255], but then was changed to be float values from [0,1].
+     * To accommodate both the possibilities, we first check if all the thresholdLevels are in
+     * [0,1], and if not, we divide all the levels with 255 to bring them down to the same scale.
+     */
+    private float[] constraintInRangeIfNeeded(float[] thresholdLevels) {
+        if (isAllInRange(thresholdLevels, /* minValueInclusive= */ 0.0f,
+                /* maxValueInclusive= */ 1.0f)) {
+            return thresholdLevels;
+        }
+
+        Slog.w(TAG, "Detected screen thresholdLevels on a deprecated brightness scale");
+        float[] thresholdLevelsScaled = new float[thresholdLevels.length];
+        for (int index = 0; thresholdLevels.length > index; ++index) {
+            thresholdLevelsScaled[index] = thresholdLevels[index] / 255.0f;
+        }
+        return thresholdLevelsScaled;
+    }
+
+    private boolean isAllInRange(float[] configArray, float minValueInclusive,
+            float maxValueInclusive) {
+        for (float v : configArray) {
+            if (v < minValueInclusive || v > maxValueInclusive) {
+                return false;
             }
         }
+        return true;
     }
 
     private boolean thermalStatusIsValid(ThermalStatus value) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index efd2e34..458cf1a 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -956,53 +956,77 @@
                     com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
                     1, 1);
 
-            int[] ambientBrighteningThresholds = resources.getIntArray(
-                    com.android.internal.R.array.config_ambientBrighteningThresholds);
-            int[] ambientDarkeningThresholds = resources.getIntArray(
-                    com.android.internal.R.array.config_ambientDarkeningThresholds);
-            int[] ambientThresholdLevels = resources.getIntArray(
-                    com.android.internal.R.array.config_ambientThresholdLevels);
+            // Ambient Lux - Active Mode Brightness Thresholds
+            float[] ambientBrighteningThresholds =
+                    mDisplayDeviceConfig.getAmbientBrighteningPercentages();
+            float[] ambientDarkeningThresholds =
+                    mDisplayDeviceConfig.getAmbientDarkeningPercentages();
+            float[] ambientBrighteningLevels =
+                    mDisplayDeviceConfig.getAmbientBrighteningLevels();
+            float[] ambientDarkeningLevels =
+                    mDisplayDeviceConfig.getAmbientDarkeningLevels();
             float ambientDarkeningMinThreshold =
                     mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold();
             float ambientBrighteningMinThreshold =
                     mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold();
             HysteresisLevels ambientBrightnessThresholds = new HysteresisLevels(
                     ambientBrighteningThresholds, ambientDarkeningThresholds,
-                    ambientThresholdLevels, ambientDarkeningMinThreshold,
+                    ambientBrighteningLevels, ambientDarkeningLevels, ambientDarkeningMinThreshold,
                     ambientBrighteningMinThreshold);
 
-            int[] screenBrighteningThresholds = resources.getIntArray(
-                    com.android.internal.R.array.config_screenBrighteningThresholds);
-            int[] screenDarkeningThresholds = resources.getIntArray(
-                    com.android.internal.R.array.config_screenDarkeningThresholds);
-            float[] screenThresholdLevels = BrightnessMappingStrategy.getFloatArray(resources
-                    .obtainTypedArray(com.android.internal.R.array.config_screenThresholdLevels));
+            // Display - Active Mode Brightness Thresholds
+            float[] screenBrighteningThresholds =
+                    mDisplayDeviceConfig.getScreenBrighteningPercentages();
+            float[] screenDarkeningThresholds =
+                    mDisplayDeviceConfig.getScreenDarkeningPercentages();
+            float[] screenBrighteningLevels =
+                    mDisplayDeviceConfig.getScreenBrighteningLevels();
+            float[] screenDarkeningLevels =
+                    mDisplayDeviceConfig.getScreenDarkeningLevels();
             float screenDarkeningMinThreshold =
                     mDisplayDeviceConfig.getScreenDarkeningMinThreshold();
             float screenBrighteningMinThreshold =
                     mDisplayDeviceConfig.getScreenBrighteningMinThreshold();
             HysteresisLevels screenBrightnessThresholds = new HysteresisLevels(
-                    screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
-                    screenDarkeningMinThreshold, screenBrighteningMinThreshold);
+                    screenBrighteningThresholds, screenDarkeningThresholds,
+                    screenBrighteningLevels, screenDarkeningLevels, screenDarkeningMinThreshold,
+                    screenBrighteningMinThreshold);
 
-            // Idle screen thresholds
-            float screenDarkeningMinThresholdIdle =
-                    mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle();
-            float screenBrighteningMinThresholdIdle =
-                    mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle();
-            HysteresisLevels screenBrightnessThresholdsIdle = new HysteresisLevels(
-                    screenBrighteningThresholds, screenDarkeningThresholds, screenThresholdLevels,
-                    screenDarkeningMinThresholdIdle, screenBrighteningMinThresholdIdle);
-
-            // Idle ambient thresholds
+            // Ambient Lux - Idle Screen Brightness Thresholds
             float ambientDarkeningMinThresholdIdle =
                     mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle();
             float ambientBrighteningMinThresholdIdle =
                     mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle();
+            float[] ambientBrighteningThresholdsIdle =
+                    mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle();
+            float[] ambientDarkeningThresholdsIdle =
+                    mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle();
+            float[] ambientBrighteningLevelsIdle =
+                    mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle();
+            float[] ambientDarkeningLevelsIdle =
+                    mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle();
             HysteresisLevels ambientBrightnessThresholdsIdle = new HysteresisLevels(
-                    ambientBrighteningThresholds, ambientDarkeningThresholds,
-                    ambientThresholdLevels, ambientDarkeningMinThresholdIdle,
-                    ambientBrighteningMinThresholdIdle);
+                    ambientBrighteningThresholdsIdle, ambientDarkeningThresholdsIdle,
+                    ambientBrighteningLevelsIdle, ambientDarkeningLevelsIdle,
+                    ambientDarkeningMinThresholdIdle, ambientBrighteningMinThresholdIdle);
+
+            // Display - Idle Screen Brightness Thresholds
+            float screenDarkeningMinThresholdIdle =
+                    mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle();
+            float screenBrighteningMinThresholdIdle =
+                    mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle();
+            float[] screenBrighteningThresholdsIdle =
+                    mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle();
+            float[] screenDarkeningThresholdsIdle =
+                    mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle();
+            float[] screenBrighteningLevelsIdle =
+                    mDisplayDeviceConfig.getScreenBrighteningLevelsIdle();
+            float[] screenDarkeningLevelsIdle =
+                    mDisplayDeviceConfig.getScreenDarkeningLevelsIdle();
+            HysteresisLevels screenBrightnessThresholdsIdle = new HysteresisLevels(
+                    screenBrighteningThresholdsIdle, screenDarkeningThresholdsIdle,
+                    screenBrighteningLevelsIdle, screenDarkeningLevelsIdle,
+                    screenDarkeningMinThresholdIdle, screenBrighteningMinThresholdIdle);
 
             long brighteningLightDebounce = mDisplayDeviceConfig
                     .getAutoBrightnessBrighteningLightDebounce();
diff --git a/services/core/java/com/android/server/display/HysteresisLevels.java b/services/core/java/com/android/server/display/HysteresisLevels.java
index abf8fe3..faa4c3d 100644
--- a/services/core/java/com/android/server/display/HysteresisLevels.java
+++ b/services/core/java/com/android/server/display/HysteresisLevels.java
@@ -29,52 +29,38 @@
 
     private static final boolean DEBUG = false;
 
-    private final float[] mBrighteningThresholds;
-    private final float[] mDarkeningThresholds;
-    private final float[] mThresholdLevels;
+    private final float[] mBrighteningThresholdsPercentages;
+    private final float[] mDarkeningThresholdsPercentages;
+    private final float[] mBrighteningThresholdLevels;
+    private final float[] mDarkeningThresholdLevels;
     private final float mMinDarkening;
     private final float mMinBrightening;
 
     /**
-     * Creates a {@code HysteresisLevels} object for ambient brightness.
-     * @param brighteningThresholds an array of brightening hysteresis constraint constants.
-     * @param darkeningThresholds an array of darkening hysteresis constraint constants.
-     * @param thresholdLevels a monotonically increasing array of threshold levels.
-     * @param minBrighteningThreshold the minimum value for which the brightening value needs to
-     *                                return.
-     * @param minDarkeningThreshold the minimum value for which the darkening value needs to return.
-    */
-    HysteresisLevels(int[] brighteningThresholds, int[] darkeningThresholds,
-            int[] thresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold) {
-        if (brighteningThresholds.length != darkeningThresholds.length
-                || darkeningThresholds.length != thresholdLevels.length + 1) {
-            throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
-        }
-        mBrighteningThresholds = setArrayFormat(brighteningThresholds, 1000.0f);
-        mDarkeningThresholds = setArrayFormat(darkeningThresholds, 1000.0f);
-        mThresholdLevels = setArrayFormat(thresholdLevels, 1.0f);
-        mMinDarkening = minDarkeningThreshold;
-        mMinBrightening = minBrighteningThreshold;
-    }
-
-    /**
-     * Creates a {@code HysteresisLevels} object for screen brightness.
-     * @param brighteningThresholds an array of brightening hysteresis constraint constants.
-     * @param darkeningThresholds an array of darkening hysteresis constraint constants.
-     * @param thresholdLevels a monotonically increasing array of threshold levels.
+     * Creates a {@code HysteresisLevels} object with the given equal-length
+     * float arrays.
+     * @param brighteningThresholdsPercentages 0-100 of thresholds
+     * @param darkeningThresholdsPercentages 0-100 of thresholds
+     * @param brighteningThresholdLevels float array of brightness values in the relevant units
+     * @param darkeningThresholdLevels float array of brightness values in the relevant units
      * @param minBrighteningThreshold the minimum value for which the brightening value needs to
      *                                return.
      * @param minDarkeningThreshold the minimum value for which the darkening value needs to return.
      */
-    HysteresisLevels(int[] brighteningThresholds, int[] darkeningThresholds,
-            float[] thresholdLevels, float minDarkeningThreshold, float minBrighteningThreshold) {
-        if (brighteningThresholds.length != darkeningThresholds.length
-                || darkeningThresholds.length != thresholdLevels.length + 1) {
+    HysteresisLevels(float[] brighteningThresholdsPercentages,
+            float[] darkeningThresholdsPercentages,
+            float[] brighteningThresholdLevels, float[] darkeningThresholdLevels,
+            float minDarkeningThreshold, float minBrighteningThreshold) {
+        if (brighteningThresholdsPercentages.length != brighteningThresholdLevels.length
+                || darkeningThresholdsPercentages.length != darkeningThresholdLevels.length) {
             throw new IllegalArgumentException("Mismatch between hysteresis array lengths.");
         }
-        mBrighteningThresholds = setArrayFormat(brighteningThresholds, 1000.0f);
-        mDarkeningThresholds = setArrayFormat(darkeningThresholds, 1000.0f);
-        mThresholdLevels = constraintInRangeIfNeeded(thresholdLevels);
+        mBrighteningThresholdsPercentages =
+                setArrayFormat(brighteningThresholdsPercentages, 100.0f);
+        mDarkeningThresholdsPercentages =
+                setArrayFormat(darkeningThresholdsPercentages, 100.0f);
+        mBrighteningThresholdLevels = setArrayFormat(brighteningThresholdLevels, 1.0f);
+        mDarkeningThresholdLevels = setArrayFormat(darkeningThresholdLevels, 1.0f);
         mMinDarkening = minDarkeningThreshold;
         mMinBrightening = minBrighteningThreshold;
     }
@@ -83,7 +69,9 @@
      * Return the brightening hysteresis threshold for the given value level.
      */
     public float getBrighteningThreshold(float value) {
-        final float brightConstant = getReferenceLevel(value, mBrighteningThresholds);
+        final float brightConstant = getReferenceLevel(value,
+                mBrighteningThresholdLevels, mBrighteningThresholdsPercentages);
+
         float brightThreshold = value * (1.0f + brightConstant);
         if (DEBUG) {
             Slog.d(TAG, "bright hysteresis constant=" + brightConstant + ", threshold="
@@ -98,7 +86,8 @@
      * Return the darkening hysteresis threshold for the given value level.
      */
     public float getDarkeningThreshold(float value) {
-        final float darkConstant = getReferenceLevel(value, mDarkeningThresholds);
+        final float darkConstant = getReferenceLevel(value,
+                mDarkeningThresholdLevels, mDarkeningThresholdsPercentages);
         float darkThreshold = value * (1.0f - darkConstant);
         if (DEBUG) {
             Slog.d(TAG, "dark hysteresis constant=: " + darkConstant + ", threshold="
@@ -111,60 +100,39 @@
     /**
      * Return the hysteresis constant for the closest threshold value from the given array.
      */
-    private float getReferenceLevel(float value, float[] referenceLevels) {
-        int index = 0;
-        while (mThresholdLevels.length > index && value >= mThresholdLevels[index]) {
-            ++index;
+    private float getReferenceLevel(float value, float[] thresholdLevels,
+            float[] thresholdPercentages) {
+        if (thresholdLevels == null || thresholdLevels.length == 0 || value < thresholdLevels[0]) {
+            return 0.0f;
         }
-        return referenceLevels[index];
+        int index = 0;
+        while (index < thresholdLevels.length - 1 && value >= thresholdLevels[index + 1]) {
+            index++;
+        }
+        return thresholdPercentages[index];
     }
 
     /**
      * Return a float array where each i-th element equals {@code configArray[i]/divideFactor}.
      */
-    private float[] setArrayFormat(int[] configArray, float divideFactor) {
+    private float[] setArrayFormat(float[] configArray, float divideFactor) {
         float[] levelArray = new float[configArray.length];
         for (int index = 0; levelArray.length > index; ++index) {
-            levelArray[index] = (float) configArray[index] / divideFactor;
+            levelArray[index] = configArray[index] / divideFactor;
         }
         return levelArray;
     }
 
-    /**
-     * This check is due to historical reasons, where screen thresholdLevels used to be
-     * integer values in the range of [0-255], but then was changed to be float values from [0,1].
-     * To accommodate both the possibilities, we first check if all the thresholdLevels are in [0,
-     * 1], and if not, we divide all the levels with 255 to bring them down to the same scale.
-     */
-    private float[] constraintInRangeIfNeeded(float[] thresholdLevels) {
-        if (isAllInRange(thresholdLevels, /* minValueInclusive = */ 0.0f, /* maxValueInclusive = */
-                1.0f)) {
-            return thresholdLevels;
-        }
-
-        Slog.w(TAG, "Detected screen thresholdLevels on a deprecated brightness scale");
-        float[] thresholdLevelsScaled = new float[thresholdLevels.length];
-        for (int index = 0; thresholdLevels.length > index; ++index) {
-            thresholdLevelsScaled[index] = thresholdLevels[index] / 255.0f;
-        }
-        return thresholdLevelsScaled;
-    }
-
-    private boolean isAllInRange(float[] configArray, float minValueInclusive,
-            float maxValueInclusive) {
-        int configArraySize = configArray.length;
-        for (int index = 0; configArraySize > index; ++index) {
-            if (configArray[index] < minValueInclusive || configArray[index] > maxValueInclusive) {
-                return false;
-            }
-        }
-        return true;
-    }
 
     void dump(PrintWriter pw) {
         pw.println("HysteresisLevels");
-        pw.println("  mBrighteningThresholds=" + Arrays.toString(mBrighteningThresholds));
-        pw.println("  mDarkeningThresholds=" + Arrays.toString(mDarkeningThresholds));
-        pw.println("  mThresholdLevels=" + Arrays.toString(mThresholdLevels));
+        pw.println("  mBrighteningThresholdLevels=" + Arrays.toString(mBrighteningThresholdLevels));
+        pw.println("  mBrighteningThresholdsPercentages="
+                + Arrays.toString(mBrighteningThresholdsPercentages));
+        pw.println("  mMinBrightening=" + mMinBrightening);
+        pw.println("  mDarkeningThresholdLevels=" + Arrays.toString(mDarkeningThresholdLevels));
+        pw.println("  mDarkeningThresholdsPercentages="
+                + Arrays.toString(mDarkeningThresholdsPercentages));
+        pw.println("  mMinDarkening=" + mMinDarkening);
     }
 }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index efb2cb7..2a21928 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -411,8 +411,11 @@
 
             // For a new display, we need to initialize the default mode ID.
             if (mDefaultModeId == INVALID_MODE_ID) {
-                mDefaultModeId = activeRecord.mMode.getModeId();
-                mDefaultModeGroup = mActiveSfDisplayMode.group;
+                mDefaultModeId = mSystemPreferredModeId != INVALID_MODE_ID
+                        ? mSystemPreferredModeId : activeRecord.mMode.getModeId();
+                mDefaultModeGroup = mSystemPreferredModeId != INVALID_MODE_ID
+                        ? preferredSfDisplayMode.group
+                        : 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.");
@@ -894,13 +897,6 @@
         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/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index a7e1a28..cd36dd0 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -885,7 +885,7 @@
                     }
                 });
             }
-        } else {
+        } else if (!networkInfo.isConnectedOrConnecting()) {
             mConnectedDeviceGroupInfo = null;
 
             // Disconnect if we lost the network while connecting or connected to a display.
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 4e4f454..b8af1bf 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -118,7 +118,7 @@
 
     public void startDream(Binder token, ComponentName name,
             boolean isPreviewMode, boolean canDoze, int userId, PowerManager.WakeLock wakeLock,
-            ComponentName overlayComponentName) {
+            ComponentName overlayComponentName, String reason) {
         stopDream(true /*immediate*/, "starting new dream");
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
@@ -128,7 +128,7 @@
 
             Slog.i(TAG, "Starting dream: name=" + name
                     + ", isPreviewMode=" + isPreviewMode + ", canDoze=" + canDoze
-                    + ", userId=" + userId);
+                    + ", userId=" + userId + ", reason='" + reason + "'");
 
             mCurrentDream = new DreamRecord(token, name, isPreviewMode, canDoze, userId, wakeLock);
 
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index fee1f5c..7964fd5 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -60,6 +60,7 @@
 import android.view.Display;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.UiEventLoggerImpl;
 import com.android.internal.util.DumpUtils;
@@ -84,6 +85,9 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "DreamManagerService";
 
+    private static final String DOZE_WAKE_LOCK_TAG = "dream:doze";
+    private static final String DREAM_WAKE_LOCK_TAG = "dream:dream";
+
     private final Object mLock = new Object();
 
     private final Context mContext;
@@ -98,17 +102,11 @@
     private final ComponentName mAmbientDisplayComponent;
     private final boolean mDismissDreamOnActivityStart;
 
-    private Binder mCurrentDreamToken;
-    private ComponentName mCurrentDreamName;
-    private int mCurrentDreamUserId;
-    private boolean mCurrentDreamIsPreview;
-    private boolean mCurrentDreamCanDoze;
-    private boolean mCurrentDreamIsDozing;
-    private boolean mCurrentDreamIsWaking;
+    @GuardedBy("mLock")
+    private DreamRecord mCurrentDream;
+
     private boolean mForceAmbientDisplayEnabled;
-    private boolean mDreamsOnlyEnabledForSystemUser;
-    private int mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
-    private int mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+    private final boolean mDreamsOnlyEnabledForSystemUser;
 
     // A temporary dream component that, when present, takes precedence over user configured dream
     // component.
@@ -116,7 +114,7 @@
 
     private ComponentName mDreamOverlayServiceName;
 
-    private AmbientDisplayConfiguration mDozeConfig;
+    private final AmbientDisplayConfiguration mDozeConfig;
     private final ActivityInterceptorCallback mActivityInterceptorCallback =
             new ActivityInterceptorCallback() {
                 @Nullable
@@ -132,8 +130,14 @@
                     final boolean activityAllowed = activityType == ACTIVITY_TYPE_HOME
                             || activityType == ACTIVITY_TYPE_DREAM
                             || activityType == ACTIVITY_TYPE_ASSISTANT;
-                    if (mCurrentDreamToken != null && !mCurrentDreamIsWaking
-                            && !mCurrentDreamIsDozing && !activityAllowed) {
+
+                    boolean shouldRequestAwaken;
+                    synchronized (mLock) {
+                        shouldRequestAwaken = mCurrentDream != null && !mCurrentDream.isWaking
+                                && !mCurrentDream.isDozing && !activityAllowed;
+                    }
+
+                    if (shouldRequestAwaken) {
                         requestAwakenInternal(
                                 "stopping dream due to activity start: " + activityInfo.name);
                     }
@@ -149,7 +153,7 @@
         mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mPowerManagerInternal = getLocalService(PowerManagerInternal.class);
         mAtmInternal = getLocalService(ActivityTaskManagerInternal.class);
-        mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, TAG);
+        mDozeWakeLock = mPowerManager.newWakeLock(PowerManager.DOZE_WAKE_LOCK, DOZE_WAKE_LOCK_TAG);
         mDozeConfig = new AmbientDisplayConfiguration(mContext);
         mUiEventLogger = new UiEventLoggerImpl();
         mDreamUiEventLogger = new DreamUiEventLoggerImpl(
@@ -197,43 +201,38 @@
     }
 
     private void dumpInternal(PrintWriter pw) {
-        pw.println("DREAM MANAGER (dumpsys dreams)");
-        pw.println();
-        pw.println("mCurrentDreamToken=" + mCurrentDreamToken);
-        pw.println("mCurrentDreamName=" + mCurrentDreamName);
-        pw.println("mCurrentDreamUserId=" + mCurrentDreamUserId);
-        pw.println("mCurrentDreamIsPreview=" + mCurrentDreamIsPreview);
-        pw.println("mCurrentDreamCanDoze=" + mCurrentDreamCanDoze);
-        pw.println("mCurrentDreamIsDozing=" + mCurrentDreamIsDozing);
-        pw.println("mCurrentDreamIsWaking=" + mCurrentDreamIsWaking);
-        pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled);
-        pw.println("mDreamsOnlyEnabledForSystemUser=" + mDreamsOnlyEnabledForSystemUser);
-        pw.println("mCurrentDreamDozeScreenState="
-                + Display.stateToString(mCurrentDreamDozeScreenState));
-        pw.println("mCurrentDreamDozeScreenBrightness=" + mCurrentDreamDozeScreenBrightness);
-        pw.println("getDozeComponent()=" + getDozeComponent());
-        pw.println();
+        synchronized (mLock) {
+            pw.println("DREAM MANAGER (dumpsys dreams)");
+            pw.println();
+            pw.println("mCurrentDream=" + mCurrentDream);
+            pw.println("mForceAmbientDisplayEnabled=" + mForceAmbientDisplayEnabled);
+            pw.println("mDreamsOnlyEnabledForSystemUser=" + mDreamsOnlyEnabledForSystemUser);
+            pw.println("getDozeComponent()=" + getDozeComponent());
+            pw.println();
 
-        DumpUtils.dumpAsync(mHandler, new DumpUtils.Dump() {
-            @Override
-            public void dump(PrintWriter pw, String prefix) {
-                mController.dump(pw);
-            }
-        }, pw, "", 200);
+            DumpUtils.dumpAsync(mHandler, (pw1, prefix) -> mController.dump(pw1), pw, "", 200);
+        }
     }
 
     /** Whether a real dream is occurring. */
     private boolean isDreamingInternal() {
         synchronized (mLock) {
-            return mCurrentDreamToken != null && !mCurrentDreamIsPreview
-                    && !mCurrentDreamIsWaking;
+            return mCurrentDream != null && !mCurrentDream.isPreview
+                    && !mCurrentDream.isWaking;
+        }
+    }
+
+    /** Whether a doze is occurring. */
+    private boolean isDozingInternal() {
+        synchronized (mLock) {
+            return mCurrentDream != null && mCurrentDream.isDozing;
         }
     }
 
     /** Whether a real dream, or a dream preview is occurring. */
     private boolean isDreamingOrInPreviewInternal() {
         synchronized (mLock) {
-            return mCurrentDreamToken != null && !mCurrentDreamIsWaking;
+            return mCurrentDream != null && !mCurrentDream.isWaking;
         }
     }
 
@@ -273,7 +272,7 @@
         // locks are held and the user activity timeout has expired then the
         // device may simply go to sleep.
         synchronized (mLock) {
-            if (mCurrentDreamToken == token) {
+            if (mCurrentDream != null && mCurrentDream.token == token) {
                 stopDreamLocked(immediate, "finished self");
             }
         }
@@ -281,16 +280,17 @@
 
     private void testDreamInternal(ComponentName dream, int userId) {
         synchronized (mLock) {
-            startDreamLocked(dream, true /*isPreviewMode*/, false /*canDoze*/, userId);
+            startDreamLocked(dream, true /*isPreviewMode*/, false /*canDoze*/, userId,
+                    "test dream" /*reason*/);
         }
     }
 
-    private void startDreamInternal(boolean doze) {
+    private void startDreamInternal(boolean doze, String reason) {
         final int userId = ActivityManager.getCurrentUser();
         final ComponentName dream = chooseDreamForUser(doze, userId);
         if (dream != null) {
             synchronized (mLock) {
-                startDreamLocked(dream, false /*isPreviewMode*/, doze, userId);
+                startDreamLocked(dream, false /*isPreviewMode*/, doze, userId, reason);
             }
         }
     }
@@ -314,13 +314,13 @@
         }
 
         synchronized (mLock) {
-            if (mCurrentDreamToken == token && mCurrentDreamCanDoze) {
-                mCurrentDreamDozeScreenState = screenState;
-                mCurrentDreamDozeScreenBrightness = screenBrightness;
+            if (mCurrentDream != null && mCurrentDream.token == token && mCurrentDream.canDoze) {
+                mCurrentDream.dozeScreenState = screenState;
+                mCurrentDream.dozeScreenBrightness = screenBrightness;
                 mPowerManagerInternal.setDozeOverrideFromDreamManager(
                         screenState, screenBrightness);
-                if (!mCurrentDreamIsDozing) {
-                    mCurrentDreamIsDozing = true;
+                if (!mCurrentDream.isDozing) {
+                    mCurrentDream.isDozing = true;
                     mDozeWakeLock.acquire();
                 }
             }
@@ -333,8 +333,8 @@
         }
 
         synchronized (mLock) {
-            if (mCurrentDreamToken == token && mCurrentDreamIsDozing) {
-                mCurrentDreamIsDozing = false;
+            if (mCurrentDream != null && mCurrentDream.token == token && mCurrentDream.isDozing) {
+                mCurrentDream.isDozing = false;
                 mDozeWakeLock.release();
                 mPowerManagerInternal.setDozeOverrideFromDreamManager(
                         Display.STATE_UNKNOWN, PowerManager.BRIGHTNESS_DEFAULT);
@@ -403,7 +403,7 @@
         ComponentName[] components = componentsFromString(names);
 
         // first, ensure components point to valid services
-        List<ComponentName> validComponents = new ArrayList<ComponentName>();
+        List<ComponentName> validComponents = new ArrayList<>();
         if (components != null) {
             for (ComponentName component : components) {
                 if (validateDream(component)) {
@@ -439,8 +439,9 @@
             mSystemDreamComponent = componentName;
 
             // Switch dream if currently dreaming and not dozing.
-            if (isDreamingInternal() && !mCurrentDreamIsDozing) {
-                startDreamInternal(false);
+            if (isDreamingInternal() && !isDozingInternal()) {
+                startDreamInternal(false /*doze*/, (mSystemDreamComponent == null ? "clear" : "set")
+                        + " system dream component" /*reason*/);
             }
         }
     }
@@ -478,13 +479,16 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void startDreamLocked(final ComponentName name,
-            final boolean isPreviewMode, final boolean canDoze, final int userId) {
-        if (!mCurrentDreamIsWaking
-                && Objects.equals(mCurrentDreamName, name)
-                && mCurrentDreamIsPreview == isPreviewMode
-                && mCurrentDreamCanDoze == canDoze
-                && mCurrentDreamUserId == userId) {
+            final boolean isPreviewMode, final boolean canDoze, final int userId,
+            final String reason) {
+        if (mCurrentDream != null
+                && !mCurrentDream.isWaking
+                && Objects.equals(mCurrentDream.name, name)
+                && mCurrentDream.isPreview == isPreviewMode
+                && mCurrentDream.canDoze == canDoze
+                && mCurrentDream.userId == userId) {
             Slog.i(TAG, "Already in target dream.");
             return;
         }
@@ -493,73 +497,60 @@
 
         Slog.i(TAG, "Entering dreamland.");
 
-        final Binder newToken = new Binder();
-        mCurrentDreamToken = newToken;
-        mCurrentDreamName = name;
-        mCurrentDreamIsPreview = isPreviewMode;
-        mCurrentDreamCanDoze = canDoze;
-        mCurrentDreamUserId = userId;
+        mCurrentDream = new DreamRecord(name, userId, isPreviewMode, canDoze);
 
-        if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
+        if (!mCurrentDream.name.equals(mAmbientDisplayComponent)) {
             // TODO(b/213906448): Remove when metrics based on new atom are fully rolled out.
             mUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_START);
             mDreamUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_START,
-                    mCurrentDreamName.flattenToString());
+                    mCurrentDream.name.flattenToString());
         }
 
         PowerManager.WakeLock wakeLock = mPowerManager
-                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "startDream");
+                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DREAM_WAKE_LOCK_TAG);
+        final Binder dreamToken = mCurrentDream.token;
         mHandler.post(wakeLock.wrap(() -> {
             mAtmInternal.notifyDreamStateChanged(true);
-            mController.startDream(newToken, name, isPreviewMode, canDoze, userId, wakeLock,
-                    mDreamOverlayServiceName);
+            mController.startDream(dreamToken, name, isPreviewMode, canDoze, userId, wakeLock,
+                    mDreamOverlayServiceName, reason);
         }));
     }
 
+    @GuardedBy("mLock")
     private void stopDreamLocked(final boolean immediate, String reason) {
-        if (mCurrentDreamToken != null) {
+        if (mCurrentDream != null) {
             if (immediate) {
                 Slog.i(TAG, "Leaving dreamland.");
                 cleanupDreamLocked();
-            } else if (mCurrentDreamIsWaking) {
+            } else if (mCurrentDream.isWaking) {
                 return; // already waking
             } else {
                 Slog.i(TAG, "Gently waking up from dream.");
-                mCurrentDreamIsWaking = true;
+                mCurrentDream.isWaking = true;
             }
 
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    Slog.i(TAG, "Performing gentle wake from dream.");
-                    mController.stopDream(immediate, reason);
-                }
-            });
+            mHandler.post(() -> mController.stopDream(immediate, reason));
         }
     }
 
+    @GuardedBy("mLock")
     private void cleanupDreamLocked() {
-        if (!mCurrentDreamName.equals(mAmbientDisplayComponent)) {
+        mHandler.post(() -> mAtmInternal.notifyDreamStateChanged(false /*dreaming*/));
+
+        if (mCurrentDream == null) {
+            return;
+        }
+
+        if (!mCurrentDream.name.equals(mAmbientDisplayComponent)) {
             // TODO(b/213906448): Remove when metrics based on new atom are fully rolled out.
             mUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_STOP);
             mDreamUiEventLogger.log(DreamUiEventLogger.DreamUiEventEnum.DREAM_STOP,
-                    mCurrentDreamName.flattenToString());
+                    mCurrentDream.name.flattenToString());
         }
-        mCurrentDreamToken = null;
-        mCurrentDreamName = null;
-        mCurrentDreamIsPreview = false;
-        mCurrentDreamCanDoze = false;
-        mCurrentDreamUserId = 0;
-        mCurrentDreamIsWaking = false;
-        if (mCurrentDreamIsDozing) {
-            mCurrentDreamIsDozing = false;
+        if (mCurrentDream.isDozing) {
             mDozeWakeLock.release();
         }
-        mCurrentDreamDozeScreenState = Display.STATE_UNKNOWN;
-        mCurrentDreamDozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
-        mHandler.post(() -> {
-            mAtmInternal.notifyDreamStateChanged(false);
-        });
+        mCurrentDream = null;
     }
 
     private void checkPermission(String permission) {
@@ -606,7 +597,7 @@
         @Override
         public void onDreamStopped(Binder token) {
             synchronized (mLock) {
-                if (mCurrentDreamToken == token) {
+                if (mCurrentDream != null && mCurrentDream.token == token) {
                     cleanupDreamLocked();
                 }
             }
@@ -624,7 +615,7 @@
      * Handler for asynchronous operations performed by the dream manager.
      * Ensures operations to {@link DreamController} are single-threaded.
      */
-    private final class DreamHandler extends Handler {
+    private static final class DreamHandler extends Handler {
         public DreamHandler(Looper looper) {
             super(looper, null, true /*async*/);
         }
@@ -865,13 +856,13 @@
 
     private final class LocalService extends DreamManagerInternal {
         @Override
-        public void startDream(boolean doze) {
-            startDreamInternal(doze);
+        public void startDream(boolean doze, String reason) {
+            startDreamInternal(doze, reason);
         }
 
         @Override
-        public void stopDream(boolean immediate) {
-            stopDreamInternal(immediate, "requested stopDream");
+        public void stopDream(boolean immediate, String reason) {
+            stopDreamInternal(immediate, reason);
         }
 
         @Override
@@ -890,13 +881,47 @@
         }
     }
 
+    private static final class DreamRecord {
+        public final Binder token = new Binder();
+        public final ComponentName name;
+        public final int userId;
+        public final boolean isPreview;
+        public final boolean canDoze;
+        public boolean isDozing = false;
+        public boolean isWaking = false;
+        public int dozeScreenState = Display.STATE_UNKNOWN;
+        public int dozeScreenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+
+        DreamRecord(ComponentName name, int userId, boolean isPreview, boolean canDoze) {
+            this.name = name;
+            this.userId = userId;
+            this.isPreview = isPreview;
+            this.canDoze = canDoze;
+        }
+
+        @Override
+        public String toString() {
+            return "DreamRecord{"
+                    + "token=" + token
+                    + ", name=" + name
+                    + ", userId=" + userId
+                    + ", isPreview=" + isPreview
+                    + ", canDoze=" + canDoze
+                    + ", isDozing=" + isDozing
+                    + ", isWaking=" + isWaking
+                    + ", dozeScreenState=" + dozeScreenState
+                    + ", dozeScreenBrightness=" + dozeScreenBrightness
+                    + '}';
+        }
+    }
+
     private final Runnable mSystemPropertiesChanged = new Runnable() {
         @Override
         public void run() {
             if (DEBUG) Slog.d(TAG, "System properties changed");
             synchronized (mLock) {
-                if (mCurrentDreamName != null && mCurrentDreamCanDoze
-                        && !mCurrentDreamName.equals(getDozeComponent())) {
+                if (mCurrentDream != null &&  mCurrentDream.name != null && mCurrentDream.canDoze
+                        && !mCurrentDream.name.equals(getDozeComponent())) {
                     // May have updated the doze component, wake up
                     mPowerManager.wakeUp(SystemClock.uptimeMillis(),
                             "android.server.dreams:SYSPROP");
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 72612a0..91d5698 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -47,6 +47,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;
@@ -318,6 +319,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;
 
@@ -425,6 +429,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);
@@ -2674,6 +2679,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;
 
@@ -2686,7 +2703,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) {
@@ -2797,6 +2815,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/notification/NotificationRecordLogger.java b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
index 9a89efa..232a69b 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLogger.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLogger.java
@@ -177,11 +177,13 @@
         NOTIFICATION_CANCEL_USER_PEEK(190),
         @UiEvent(doc = "Notification was canceled due to user dismissal from the always-on display")
         NOTIFICATION_CANCEL_USER_AOD(191),
+        @UiEvent(doc = "Notification was canceled due to user dismissal from a bubble")
+        NOTIFICATION_CANCEL_USER_BUBBLE(1228),
+        @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen")
+        NOTIFICATION_CANCEL_USER_LOCKSCREEN(193),
         @UiEvent(doc = "Notification was canceled due to user dismissal from the notification"
                 + " shade.")
         NOTIFICATION_CANCEL_USER_SHADE(192),
-        @UiEvent(doc = "Notification was canceled due to user dismissal from the lockscreen")
-        NOTIFICATION_CANCEL_USER_LOCKSCREEN(193),
         @UiEvent(doc = "Notification was canceled due to an assistant adjustment update.")
         NOTIFICATION_CANCEL_ASSISTANT(906);
 
@@ -232,6 +234,10 @@
                     return NOTIFICATION_CANCEL_USER_AOD;
                 case NotificationStats.DISMISSAL_SHADE:
                     return NOTIFICATION_CANCEL_USER_SHADE;
+                case NotificationStats.DISMISSAL_BUBBLE:
+                    return NOTIFICATION_CANCEL_USER_BUBBLE;
+                case NotificationStats.DISMISSAL_LOCKSCREEN:
+                    return NOTIFICATION_CANCEL_USER_LOCKSCREEN;
                 default:
                     if (NotificationManagerService.DBG) {
                         throw new IllegalArgumentException("Unexpected surface for user-dismiss "
diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java
index 8e944b7..39d1188 100644
--- a/services/core/java/com/android/server/om/IdmapDaemon.java
+++ b/services/core/java/com/android/server/om/IdmapDaemon.java
@@ -217,6 +217,7 @@
     synchronized List<FabricatedOverlayInfo> getFabricatedOverlayInfos() {
         final ArrayList<FabricatedOverlayInfo> allInfos = new ArrayList<>();
         Connection c = null;
+        int iteratorId = -1;
         try {
             c = connect();
             final IIdmap2 service = c.getIdmap2();
@@ -225,9 +226,9 @@
                 return Collections.emptyList();
             }
 
-            service.acquireFabricatedOverlayIterator();
+            iteratorId = service.acquireFabricatedOverlayIterator();
             List<FabricatedOverlayInfo> infos;
-            while (!(infos = service.nextFabricatedOverlayInfos()).isEmpty()) {
+            while (!(infos = service.nextFabricatedOverlayInfos(iteratorId)).isEmpty()) {
                 allInfos.addAll(infos);
             }
             return allInfos;
@@ -235,8 +236,8 @@
             Slog.wtf(TAG, "failed to get all fabricated overlays", e);
         } finally {
             try {
-                if (c.getIdmap2() != null) {
-                    c.getIdmap2().releaseFabricatedOverlayIterator();
+                if (c.getIdmap2() != null && iteratorId != -1) {
+                    c.getIdmap2().releaseFabricatedOverlayIterator(iteratorId);
                 }
             } catch (RemoteException e) {
                 // ignore
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e9d5426..b7b3326 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -6546,7 +6546,7 @@
                         if (dependentState == null) {
                             continue;
                         }
-                        if (!Objects.equals(dependentState.getUserStateOrDefault(userId)
+                        if (canSetOverlayPaths(dependentState.getUserStateOrDefault(userId)
                                 .getSharedLibraryOverlayPaths()
                                 .get(libName), newOverlayPaths)) {
                             String dependentPackageName = dependent.getPackageName();
@@ -6562,7 +6562,10 @@
                 }
             }
 
-            outUpdatedPackageNames.add(targetPackageName);
+            if (canSetOverlayPaths(packageState.getUserStateOrDefault(userId).getOverlayPaths(),
+                    newOverlayPaths)) {
+                outUpdatedPackageNames.add(targetPackageName);
+            }
 
             commitPackageStateMutation(null, mutator -> {
                 mutator.forPackage(targetPackageName)
@@ -6593,6 +6596,17 @@
         return true;
     }
 
+    private boolean canSetOverlayPaths(OverlayPaths origPaths, OverlayPaths newPaths) {
+        if (Objects.equals(origPaths, newPaths)) {
+            return false;
+        }
+        if ((origPaths == null && newPaths.isEmpty())
+                || (newPaths == null && origPaths.isEmpty())) {
+            return false;
+        }
+        return true;
+    }
+
     private void maybeUpdateSystemOverlays(String targetPackageName, OverlayPaths newOverlayPaths) {
         if (!mResolverReplaced) {
             if (targetPackageName.equals("android")) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 0c601bf..890c891 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1962,10 +1962,15 @@
 
                             continue;
                         case TAG_SHORTCUT:
-                            final ShortcutInfo si = parseShortcut(parser, packageName,
-                                    shortcutUser.getUserId(), fromBackup);
-                            // Don't use addShortcut(), we don't need to save the icon.
-                            ret.mShortcuts.put(si.getId(), si);
+                            try {
+                                final ShortcutInfo si = parseShortcut(parser, packageName,
+                                        shortcutUser.getUserId(), fromBackup);
+                                // Don't use addShortcut(), we don't need to save the icon.
+                                ret.mShortcuts.put(si.getId(), si);
+                            } catch (Exception e) {
+                                // b/246540168 malformed shortcuts should be ignored
+                                Slog.e(TAG, "Failed parsing shortcut.", e);
+                            }
                             continue;
                         case TAG_SHARE_TARGET:
                             ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 05cb429..32ef014 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -63,7 +63,6 @@
 import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD;
 import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_OTHER;
 import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
-import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
 import static android.view.WindowManagerGlobal.ADD_OKAY;
 import static android.view.WindowManagerGlobal.ADD_PERMISSION_DENIED;
 
@@ -1597,7 +1596,7 @@
         // If there's a dream running then use home to escape the dream
         // but don't actually go home.
         if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
-            mDreamManagerInternal.stopDream(false /*immediate*/);
+            mDreamManagerInternal.stopDream(false /*immediate*/, "short press on home" /*reason*/);
             return;
         }
 
@@ -2816,9 +2815,8 @@
                 break;
             case KeyEvent.KEYCODE_S:
                 if (down && event.isMetaPressed() && event.isCtrlPressed() && repeatCount == 0) {
-                    int type = event.isShiftPressed() ? TAKE_SCREENSHOT_SELECTED_REGION
-                            : TAKE_SCREENSHOT_FULLSCREEN;
-                    interceptScreenshotChord(type, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
+                    interceptScreenshotChord(
+                            TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
                     return key_consumed;
                 }
                 break;
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 dbf05f1..f200564 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1169,6 +1169,7 @@
                 return;
             }
 
+            Slog.i(TAG, "onFlip(): Face " + (isFaceDown ? "down." : "up."));
             mIsFaceDown = isFaceDown;
             if (isFaceDown) {
                 final long currentTime = mClock.uptimeMillis();
@@ -1888,12 +1889,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)) {
@@ -1944,11 +1946,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);
         }
 
@@ -1983,7 +1986,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;
@@ -1993,7 +1996,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;
@@ -2020,7 +2023,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;
@@ -2043,11 +2047,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) {
@@ -2058,10 +2062,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;
@@ -2122,8 +2128,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;
                 mDozeStartInProgress = true;
@@ -3218,8 +3226,10 @@
         if (mDreamManager != null) {
             // Restart the dream whenever the sandman is summoned.
             if (startDreaming) {
-                mDreamManager.stopDream(/* immediate= */ false);
-                mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING);
+                mDreamManager.stopDream(/* immediate= */ false,
+                        "power manager request before starting dream" /*reason*/);
+                mDreamManager.startDream(wakefulness == WAKEFULNESS_DOZING,
+                        "power manager request" /*reason*/);
             }
             isDreaming = mDreamManager.isDreaming();
         } else {
@@ -3304,7 +3314,7 @@
 
         // Stop dream.
         if (isDreaming) {
-            mDreamManager.stopDream(/* immediate= */ false);
+            mDreamManager.stopDream(/* immediate= */ false, "power manager request" /*reason*/);
         }
     }
 
@@ -4207,7 +4217,7 @@
     void onUserActivity() {
         synchronized (mLock) {
             mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).setLastUserActivityTimeLocked(
-                    mClock.uptimeMillis());
+                    mClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_OTHER);
         }
     }
 
@@ -5590,7 +5600,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/powerstats/PowerStatsDataStorage.java b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
index 8b30995..d8e6c26 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsDataStorage.java
@@ -53,7 +53,7 @@
 
     private static class DataElement {
         private static final int LENGTH_FIELD_WIDTH = 4;
-        private static final int MAX_DATA_ELEMENT_SIZE = 1000;
+        private static final int MAX_DATA_ELEMENT_SIZE = 32768;
 
         private byte[] mData;
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f888ff6..2888b9a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -602,9 +602,12 @@
         synchronized (mUserTrustState) {
             wasTrusted = (mUserTrustState.get(userId) == TrustState.TRUSTED);
             wasTrustable = (mUserTrustState.get(userId) == TrustState.TRUSTABLE);
+            boolean isAutomotive = getContext().getPackageManager().hasSystemFeature(
+                    PackageManager.FEATURE_AUTOMOTIVE);
             boolean renewingTrust = wasTrustable && (
                     (flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0);
-            boolean canMoveToTrusted = alreadyUnlocked || isFromUnlock || renewingTrust;
+            boolean canMoveToTrusted =
+                    alreadyUnlocked || isFromUnlock || renewingTrust || isAutomotive;
             boolean upgradingTrustForCurrentUser = (userId == mCurrentUser);
 
             if (trustedByAtLeastOneAgent && wasTrusted) {
@@ -687,7 +690,7 @@
      */
     public void lockUser(int userId) {
         mLockPatternUtils.requireStrongAuth(
-                StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED, userId);
+                StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
         try {
             WindowManagerGlobal.getWindowManagerService().lockNow(null);
         } catch (RemoteException e) {
@@ -2084,7 +2087,7 @@
             if (mStrongAuthTracker.isTrustAllowedForUser(mUserId)) {
                 if (DEBUG) Slog.d(TAG, "Revoking all trust because of trust timeout");
                 mLockPatternUtils.requireStrongAuth(
-                        mStrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED, mUserId);
+                        mStrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, mUserId);
             }
             maybeLockScreen(mUserId);
         }
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index d2a00af..eca2e74 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -27,6 +27,8 @@
 import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IMMERSIVE;
@@ -332,8 +334,8 @@
     }
 
     @Override
-    public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode,
-            Intent resultData) {
+    public boolean navigateUpTo(IBinder token, Intent destIntent, String resolvedType,
+            int resultCode, Intent resultData) {
         final ActivityRecord r;
         synchronized (mGlobalLock) {
             r = ActivityRecord.isInRootTaskLocked(token);
@@ -348,7 +350,7 @@
 
         synchronized (mGlobalLock) {
             return r.getRootTask().navigateUpTo(
-                    r, destIntent, destGrants, resultCode, resultData, resultGrants);
+                    r, destIntent, resolvedType, destGrants, resultCode, resultData, resultGrants);
         }
     }
 
@@ -707,7 +709,26 @@
         try {
             synchronized (mGlobalLock) {
                 final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
-                return r != null && r.setOccludesParent(true);
+                // Create a transition if the activity is playing in case the below activity didn't
+                // commit invisible. That's because if any activity below this one has changed its
+                // visibility while playing transition, there won't able to commit visibility until
+                // the running transition finish.
+                final Transition transition = r != null
+                        && r.mTransitionController.inPlayingTransition(r)
+                        ? r.mTransitionController.createTransition(TRANSIT_TO_BACK) : null;
+                if (transition != null) {
+                    r.mTransitionController.requestStartTransition(transition, null /*startTask */,
+                            null /* remoteTransition */, null /* displayChange */);
+                }
+                final boolean changed = r != null && r.setOccludesParent(true);
+                if (transition != null) {
+                    if (changed) {
+                        r.mTransitionController.setReady(r.getDisplayContent());
+                    } else {
+                        transition.abort();
+                    }
+                }
+                return changed;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -728,7 +749,25 @@
                 if (under != null) {
                     under.returningOptions = safeOptions != null ? safeOptions.getOptions(r) : null;
                 }
-                return r.setOccludesParent(false);
+                // Create a transition if the activity is playing in case the current activity
+                // didn't commit invisible. That's because if this activity has changed its
+                // visibility while playing transition, there won't able to commit visibility until
+                // the running transition finish.
+                final Transition transition = r.mTransitionController.inPlayingTransition(r)
+                        ? r.mTransitionController.createTransition(TRANSIT_TO_FRONT) : null;
+                if (transition != null) {
+                    r.mTransitionController.requestStartTransition(transition, null /*startTask */,
+                            null /* remoteTransition */, null /* displayChange */);
+                }
+                final boolean changed = r.setOccludesParent(false);
+                if (transition != null) {
+                    if (changed) {
+                        r.mTransitionController.setReady(r.getDisplayContent());
+                    } else {
+                        transition.abort();
+                    }
+                }
+                return changed;
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b8486e7..9c080e8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -120,6 +120,8 @@
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
 import static android.view.WindowManager.TRANSIT_OLD_UNSET;
+import static android.window.TransitionInfo.FLAG_IS_OCCLUDED;
+import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
@@ -658,7 +660,7 @@
     private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
             new WindowState.UpdateReportedVisibilityResults();
 
-    boolean mUseTransferredAnimation;
+    int mTransitionChangeFlags;
 
     /** Whether we need to setup the animation to animate only within the letterbox. */
     private boolean mNeedsLetterboxedAnimation;
@@ -4395,10 +4397,10 @@
                     // When transferring an animation, we no longer need to apply an animation to
                     // the token we transfer the animation over. Thus, set this flag to indicate
                     // we've transferred the animation.
-                    mUseTransferredAnimation = true;
+                    mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
                 } else if (mTransitionController.getTransitionPlayer() != null) {
                     // In the new transit system, just set this every time we transfer the window
-                    mUseTransferredAnimation = true;
+                    mTransitionChangeFlags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
                 }
                 // Post cleanup after the visibility and animation are transferred.
                 fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow);
@@ -5247,6 +5249,10 @@
 
         // If in a transition, defer commits for activities that are going invisible
         if (!visible && inTransition()) {
+            if (mTransitionController.inPlayingTransition(this)
+                    && mTransitionController.isCollecting(this)) {
+                mTransitionChangeFlags |= FLAG_IS_OCCLUDED;
+            }
             return;
         }
         // If we are preparing an app transition, then delay changing
@@ -5297,7 +5303,7 @@
     @Override
     boolean applyAnimation(LayoutParams lp, @TransitionOldType int transit, boolean enter,
             boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) {
-        if (mUseTransferredAnimation) {
+        if ((mTransitionChangeFlags & FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT) != 0) {
             return false;
         }
         // If it was set to true, reset the last request to force the transition.
@@ -5370,7 +5376,7 @@
             mWmService.mWindowPlacerLocked.performSurfacePlacement();
         }
         displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
-        mUseTransferredAnimation = false;
+        mTransitionChangeFlags = 0;
 
         postApplyAnimation(visible, fromTransition);
     }
@@ -5812,8 +5818,8 @@
         // in untrusted mode. Traverse bottom to top with boundary so that it will only check
         // activities above this activity.
         final ActivityRecord differentUidOverlayActivity = getTask().getActivity(
-                a -> a.getUid() != getUid(), this /* boundary */, false /* includeBoundary */,
-                false /* traverseTopToBottom */);
+                a -> !a.finishing && a.getUid() != getUid(), this /* boundary */,
+                false /* includeBoundary */, false /* traverseTopToBottom */);
         return differentUidOverlayActivity != null;
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 0707b81..30454d4 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -50,6 +50,7 @@
 import android.util.SparseArray;
 import android.view.RemoteAnimationAdapter;
 import android.view.WindowManager;
+import android.window.RemoteTransition;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -563,14 +564,39 @@
             return false;
         }
         mService.mRootWindowContainer.startPowerModeLaunchIfNeeded(true /* forceSend */, r);
-        final ActivityMetricsLogger.LaunchingState launchingState =
-                mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
-        final Task task = r.getTask();
-        mService.deferWindowLayout();
-        try {
+        final RemoteTransition remote = options.getRemoteTransition();
+        if (remote != null && rootTask.mTransitionController.isCollecting()) {
+            final Transition transition = new Transition(WindowManager.TRANSIT_TO_FRONT,
+                    0 /* flags */, rootTask.mTransitionController,
+                    mService.mWindowManager.mSyncEngine);
+            // Special case: we are entering recents while an existing transition is running. In
+            // this case, we know it's safe to "defer" the activity launch, so lets do so now so
+            // that it can get its own transition and thus update launcher correctly.
+            mService.mWindowManager.mSyncEngine.queueSyncSet(
+                    () -> rootTask.mTransitionController.moveToCollecting(transition),
+                    () -> {
+                        final Task task = r.getTask();
+                        task.mTransitionController.requestStartTransition(transition,
+                                task, remote, null /* displayChange */);
+                        task.mTransitionController.collect(task);
+                        startExistingRecentsIfPossibleInner(intent, options, r, task, rootTask);
+                    });
+        } else {
+            final Task task = r.getTask();
             task.mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_TO_FRONT,
                     0 /* flags */, task, task /* readyGroupRef */,
                     options.getRemoteTransition(), null /* displayChange */);
+            startExistingRecentsIfPossibleInner(intent, options, r, task, rootTask);
+        }
+        return true;
+    }
+
+    void startExistingRecentsIfPossibleInner(Intent intent, ActivityOptions options,
+            ActivityRecord r, Task task, Task rootTask) {
+        final ActivityMetricsLogger.LaunchingState launchingState =
+                mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+        mService.deferWindowLayout();
+        try {
             r.mTransitionController.setTransientLaunch(r,
                     TaskDisplayArea.getRootTaskAbove(rootTask));
             task.moveToFront("startExistingRecents");
@@ -582,7 +608,6 @@
             task.mInResumeTopActivity = false;
             mService.continueWindowLayout();
         }
-        return true;
     }
 
     void registerRemoteAnimationForNextActivityStart(String packageName,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index a870b8a..e3916cb 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1481,7 +1481,7 @@
             handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
                     mRootWindowContainer.getDefaultTaskDisplayArea(), currentRootTask,
                     forceNonResizeable);
-            if (r != null) {
+            if (r != null && (options == null || !options.getDisableStartingWindow())) {
                 // Use a starting window to reduce the transition latency for reshowing the task.
                 // Note that with shell transition, this should be executed before requesting
                 // transition to avoid delaying the starting window.
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index e80c260..0bfc48b 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -98,7 +98,7 @@
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
                 return mService.getRecentTasks().createRecentTaskInfo(task,
-                        false /* stripExtras */);
+                        false /* stripExtras */, true /* getTasksAllowed */);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 5599f2c..9c95e31 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -1032,8 +1032,12 @@
     private void applyAnimations(ArraySet<ActivityRecord> openingApps,
             ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit,
             LayoutParams animLp, boolean voiceInteraction) {
+        final RecentsAnimationController rac = mService.getRecentsAnimationController();
         if (transit == WindowManager.TRANSIT_OLD_UNSET
                 || (openingApps.isEmpty() && closingApps.isEmpty())) {
+            if (rac != null) {
+                rac.sendTasksAppeared();
+            }
             return;
         }
 
@@ -1071,7 +1075,6 @@
                 voiceInteraction);
         applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
                 voiceInteraction);
-        final RecentsAnimationController rac = mService.getRecentsAnimationController();
         if (rac != null) {
             rac.sendTasksAppeared();
         }
diff --git a/services/core/java/com/android/server/wm/AsyncRotationController.java b/services/core/java/com/android/server/wm/AsyncRotationController.java
index 8c5f053..7d9ae87 100644
--- a/services/core/java/com/android/server/wm/AsyncRotationController.java
+++ b/services/core/java/com/android/server/wm/AsyncRotationController.java
@@ -202,8 +202,7 @@
         // target windows. But the windows still need to use sync transaction to keep the appearance
         // in previous rotation, so request a no-op sync to keep the state.
         for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
-            if (TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST
-                    && mTargetWindowTokens.valueAt(i).mAction != Operation.ACTION_SEAMLESS) {
+            if (mTargetWindowTokens.valueAt(i).canDrawBeforeStartTransaction()) {
                 // Expect a screenshot layer will cover the non seamless windows.
                 continue;
             }
@@ -489,7 +488,7 @@
             return false;
         }
         final Operation op = mTargetWindowTokens.get(w.mToken);
-        if (op == null) return false;
+        if (op == null || op.canDrawBeforeStartTransaction()) return false;
         if (DEBUG) Slog.d(TAG, "handleFinishDrawing " + w);
         if (op.mDrawTransaction == null) {
             if (w.isClientLocal()) {
@@ -554,5 +553,14 @@
         Operation(@Action int action) {
             mAction = action;
         }
+
+        /**
+         * Returns {@code true} if the corresponding window can draw its latest content before the
+         * start transaction of rotation transition is applied.
+         */
+        boolean canDrawBeforeStartTransaction() {
+            return TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST
+                    && mAction != ACTION_SEAMLESS;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java
index 35a744f..f304b4a 100644
--- a/services/core/java/com/android/server/wm/ContentRecorder.java
+++ b/services/core/java/com/android/server/wm/ContentRecorder.java
@@ -388,8 +388,7 @@
      * </p>
      */
     private void handleStartRecordingFailed() {
-        final boolean shouldExitTaskRecording = mContentRecordingSession != null
-                && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+        final boolean shouldExitTaskRecording = isRecordingContentTask();
         clearContentRecordingSession();
         if (shouldExitTaskRecording) {
             // Clean up the cached session first to ensure recording doesn't re-start, since
@@ -475,9 +474,10 @@
         ProtoLog.v(WM_DEBUG_CONTENT_RECORDING,
                 "Recorded task is removed, so stop recording on display %d",
                 mDisplayContent.getDisplayId());
-        Task recordedTask = mRecordedWindowContainer.asTask();
-        if (recordedTask == null
-                || mContentRecordingSession.getContentToRecord() != RECORD_CONTENT_TASK) {
+
+        Task recordedTask = mRecordedWindowContainer != null
+                ? mRecordedWindowContainer.asTask() : null;
+        if (recordedTask == null || !isRecordingContentTask()) {
             return;
         }
         recordedTask.unregisterWindowContainerListener(this);
@@ -501,4 +501,9 @@
     @VisibleForTesting interface MediaProjectionManagerWrapper {
         void stopActiveProjection();
     }
+
+    private boolean isRecordingContentTask() {
+        return mContentRecordingSession != null
+                && mContentRecordingSession.getContentToRecord() == RECORD_CONTENT_TASK;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 95d71a3..71c80fb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6729,4 +6729,11 @@
     DisplayContent asDisplayContent() {
         return this;
     }
+
+    @Override
+    @Surface.Rotation
+    int getRelativeDisplayRotation() {
+        // Display is the root, so it's not rotated relative to anything.
+        return Surface.ROTATION_0;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index b26de07..42a3ec6 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2168,10 +2168,7 @@
      * If the decor insets changes, the display configuration may be affected. The caller should
      * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}.
      */
-    boolean updateDecorInsetsInfoIfNeeded(WindowState win) {
-        if (!win.providesNonDecorInsets()) {
-            return false;
-        }
+    boolean updateDecorInsetsInfo() {
         final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames;
         final int rotation = displayFrames.mRotation;
         final int dw = displayFrames.mWidth;
@@ -2713,7 +2710,7 @@
      *
      * @param screenshotType The type of screenshot, for example either
      *                       {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
-     *                       {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
+     *                       {@link WindowManager#TAKE_SCREENSHOT_PROVIDED_IMAGE}
      * @param source Where the screenshot originated from (see WindowManager.ScreenshotSource)
      */
     public void takeScreenshot(int screenshotType, int source) {
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 317c93e..ea82417 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -481,7 +481,7 @@
     }
 
     private void updateRoundedCorners(WindowState mainWindow) {
-        final SurfaceControl windowSurface = mainWindow.getClientViewRootSurface();
+        final SurfaceControl windowSurface = mainWindow.getSurfaceControl();
         if (windowSurface != null && windowSurface.isValid()) {
             final Transaction transaction = mActivityRecord.getSyncTransaction();
 
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 4860762..1fc061b 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -976,7 +976,7 @@
                 continue;
             }
 
-            res.add(createRecentTaskInfo(task, true /* stripExtras */));
+            res.add(createRecentTaskInfo(task, true /* stripExtras */, getTasksAllowed));
         }
         return res;
     }
@@ -1895,7 +1895,8 @@
     /**
      * Creates a new RecentTaskInfo from a Task.
      */
-    ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras) {
+    ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr, boolean stripExtras,
+            boolean getTasksAllowed) {
         final ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
         // If the recent Task is detached, we consider it will be re-attached to the default
         // TaskDisplayArea because we currently only support recent overview in the default TDA.
@@ -1907,6 +1908,9 @@
         rti.id = rti.isRunning ? rti.taskId : INVALID_TASK_ID;
         rti.persistentId = rti.taskId;
         rti.lastSnapshotData.set(tr.mLastTaskSnapshotData);
+        if (!getTasksAllowed) {
+            Task.trimIneffectiveInfo(tr, rti);
+        }
 
         // Fill in organized child task info for the task created by organizer.
         if (tr.mCreatedByOrganizer) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 5b702ea..353ca53 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -116,7 +116,7 @@
     private boolean mWillFinishToHome = false;
     private final Runnable mFailsafeRunnable = this::onFailsafe;
 
-    // The recents component app token that is shown behind the visibile tasks
+    // The recents component app token that is shown behind the visible tasks
     private ActivityRecord mTargetActivityRecord;
     private DisplayContent mDisplayContent;
     private int mTargetActivityType;
@@ -457,6 +457,22 @@
         }
     }
 
+    /**
+     * Return whether the given window should still be considered interesting for the all-drawn
+     * state.  This is only interesting for the target app, which may have child windows that are
+     * not actually visible and should not be considered interesting and waited upon.
+     */
+    protected boolean isInterestingForAllDrawn(WindowState window) {
+        if (isTargetApp(window.getActivityRecord())) {
+            if (window.getWindowType() != TYPE_BASE_APPLICATION
+                    && window.getAttrs().alpha == 0f) {
+                // If there is a cihld window that is alpha 0, then ignore that window
+                return false;
+            }
+        }
+        // By default all windows are still interesting for all drawn purposes
+        return true;
+    }
 
     /**
      * Whether a task should be filtered from the recents animation. This can be true for tasks
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 120fec0..0e60274 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -142,6 +142,10 @@
         task.fillTaskInfo(rti, !mKeepIntentExtra);
         // Fill in some deprecated values
         rti.id = rti.taskId;
+
+        if (!mAllowed) {
+            Task.trimIneffectiveInfo(task, rti);
+        }
         return rti;
     }
 }
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 8bacacd..e69a732 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -263,7 +263,7 @@
             ActivityOptions options, int callingPid, int callingUid) {
         // If a launch task id is specified, then ensure that the caller is the recents
         // component or has the START_TASKS_FROM_RECENTS permission
-        if (options.getLaunchTaskId() != INVALID_TASK_ID
+        if ((options.getLaunchTaskId() != INVALID_TASK_ID || options.getDisableStartingWindow())
                 && !supervisor.mRecentTasks.isCallerRecents(callingUid)) {
             final int startInTaskPerm = ActivityTaskManagerService.checkPermission(
                     START_TASKS_FROM_RECENTS, callingPid, callingUid);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index aede32c..6ce96ec 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3446,6 +3446,27 @@
         info.isSleeping = shouldSleepActivities();
     }
 
+    /**
+     * Removes the activity info if the activity belongs to a different uid, which is
+     * different from the app that hosts the task.
+     */
+    static void trimIneffectiveInfo(Task task, TaskInfo info) {
+        final ActivityRecord baseActivity = task.getActivity(r -> !r.finishing,
+                false /* traverseTopToBottom */);
+        final int baseActivityUid =
+                baseActivity != null ? baseActivity.getUid() : task.effectiveUid;
+
+        if (info.topActivityInfo != null
+                && task.effectiveUid != info.topActivityInfo.applicationInfo.uid) {
+            info.topActivity = null;
+            info.topActivityInfo = null;
+        }
+
+        if (task.effectiveUid != baseActivityUid) {
+            info.baseActivity = null;
+        }
+    }
+
     @Nullable PictureInPictureParams getPictureInPictureParams() {
         final Task topTask = getTopMostTask();
         if (topTask == null) return null;
@@ -3525,12 +3546,16 @@
      * {@link android.window.TaskFragmentOrganizer}
      */
     TaskFragmentParentInfo getTaskFragmentParentInfo() {
-        return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(), isVisibleRequested());
+        return new TaskFragmentParentInfo(getConfiguration(), getDisplayId(),
+                shouldBeVisible(null /* starting */));
     }
 
     @Override
     void onActivityVisibleRequestedChanged() {
-        if (mVisibleRequested != isVisibleRequested()) {
+        final boolean prevVisibleRequested = mVisibleRequested;
+        // mVisibleRequested is updated in super method.
+        super.onActivityVisibleRequestedChanged();
+        if (prevVisibleRequested != mVisibleRequested) {
             sendTaskFragmentParentInfoChangedIfNeeded();
         }
     }
@@ -5049,6 +5074,9 @@
                     == ActivityOptions.ANIM_SCENE_TRANSITION) {
                 doShow = false;
             }
+            if (options != null && options.getDisableStartingWindow()) {
+                doShow = false;
+            }
             if (r.mLaunchTaskBehind) {
                 // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we
                 // tell WindowManager that r is visible even though it is at the back of the root
@@ -5308,8 +5336,9 @@
         return false;
     }
 
-    boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants destGrants,
-            int resultCode, Intent resultData, NeededUriGrants resultGrants) {
+    boolean navigateUpTo(ActivityRecord srec, Intent destIntent, String resolvedType,
+            NeededUriGrants destGrants, int resultCode, Intent resultData,
+            NeededUriGrants resultGrants) {
         if (!srec.attachedToProcess()) {
             // Nothing to do if the caller is not attached, because this method should be called
             // from an alive activity.
@@ -5402,28 +5431,22 @@
                             srec.packageName);
                 }
             } else {
-                try {
-                    ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
-                            destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS,
-                            srec.mUserId);
-                    // TODO(b/64750076): Check if calling pid should really be -1.
-                    final int res = mAtmService.getActivityStartController()
-                            .obtainStarter(destIntent, "navigateUpTo")
-                            .setCaller(srec.app.getThread())
-                            .setActivityInfo(aInfo)
-                            .setResultTo(parent.token)
-                            .setCallingPid(-1)
-                            .setCallingUid(callingUid)
-                            .setCallingPackage(srec.packageName)
-                            .setCallingFeatureId(parent.launchedFromFeatureId)
-                            .setRealCallingPid(-1)
-                            .setRealCallingUid(callingUid)
-                            .setComponentSpecified(true)
-                            .execute();
-                    foundParentInTask = res == ActivityManager.START_SUCCESS;
-                } catch (RemoteException e) {
-                    foundParentInTask = false;
-                }
+                // TODO(b/64750076): Check if calling pid should really be -1.
+                final int res = mAtmService.getActivityStartController()
+                        .obtainStarter(destIntent, "navigateUpTo")
+                        .setResolvedType(resolvedType)
+                        .setUserId(srec.mUserId)
+                        .setCaller(srec.app.getThread())
+                        .setResultTo(parent.token)
+                        .setCallingPid(-1)
+                        .setCallingUid(callingUid)
+                        .setCallingPackage(srec.packageName)
+                        .setCallingFeatureId(parent.launchedFromFeatureId)
+                        .setRealCallingPid(-1)
+                        .setRealCallingUid(callingUid)
+                        .setComponentSpecified(true)
+                        .execute();
+                foundParentInTask = res == ActivityManager.START_SUCCESS;
                 parent.finishIfPossible(resultCode, resultData, resultGrants,
                         "navigate-top", true /* oomAdj */);
             }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 058a066..d178676 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -2690,12 +2690,26 @@
             return;
         }
         mVisibleRequested = isVisibleRequested;
-        final TaskFragment parentTf = getParent().asTaskFragment();
+        final WindowContainer<?> parent = getParent();
+        if (parent == null) {
+            return;
+        }
+        final TaskFragment parentTf = parent.asTaskFragment();
         if (parentTf != null) {
             parentTf.onActivityVisibleRequestedChanged();
         }
     }
 
+    @Nullable
+    @Override
+    TaskFragment getTaskFragment(Predicate<TaskFragment> callback) {
+        final TaskFragment taskFragment = super.getTaskFragment(callback);
+        if (taskFragment != null) {
+            return taskFragment;
+        }
+        return callback.test(this) ? this : null;
+    }
+
     String toFullString() {
         final StringBuilder sb = new StringBuilder(128);
         sb.append(this);
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 2d5c989..867833a 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -920,6 +920,7 @@
         for (int i = 0, n = pendingEvents.size(); i < n; i++) {
             final PendingTaskFragmentEvent event = pendingEvents.get(i);
             final Task task = event.mTaskFragment != null ? event.mTaskFragment.getTask() : null;
+            // TODO(b/251132298): move visibility check to the client side.
             if (task != null && (task.lastActiveTime <= event.mDeferTime
                     || !(isTaskVisible(task, visibleTasks, invisibleTasks)
                     || shouldSendEventWhenTaskInvisible(event)))) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 147c9cb..526a366 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -55,7 +55,6 @@
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
 import static android.window.TransitionInfo.FLAG_OCCLUDES_KEYGUARD;
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
-import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
 import static android.window.TransitionInfo.FLAG_WILL_IME_SHOWN;
 
@@ -1331,7 +1330,7 @@
             ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                     "        sibling is a participant with mode %s",
                     TransitionInfo.modeToString(siblingMode));
-            if (mode != siblingMode) {
+            if (reduceMode(mode) != reduceMode(siblingMode)) {
                 ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                         "          SKIP: common mode mismatch. was %s",
                         TransitionInfo.modeToString(mode));
@@ -1341,6 +1340,16 @@
         return true;
     }
 
+    /** "reduces" a mode into a smaller set of modes that uniquely represents visibility change. */
+    @TransitionInfo.TransitionMode
+    private static int reduceMode(@TransitionInfo.TransitionMode int mode) {
+        switch (mode) {
+            case TRANSIT_TO_BACK: return TRANSIT_CLOSE;
+            case TRANSIT_TO_FRONT: return TRANSIT_OPEN;
+            default: return mode;
+        }
+    }
+
     /**
      * Go through topTargets and try to promote (see {@link #canPromote}) one of them.
      *
@@ -1842,7 +1851,7 @@
         @TransitionInfo.TransitionMode
         int getTransitMode(@NonNull WindowContainer wc) {
             if ((mFlags & ChangeInfo.FLAG_ABOVE_TRANSIENT_LAUNCH) != 0) {
-                return TRANSIT_CLOSE;
+                return mExistenceChanged ? TRANSIT_CLOSE : TRANSIT_TO_BACK;
             }
             final boolean nowVisible = wc.isVisibleRequested();
             if (nowVisible == mVisible) {
@@ -1879,12 +1888,10 @@
             final ActivityRecord record = wc.asActivityRecord();
             if (record != null) {
                 parentTask = record.getTask();
-                if (record.mUseTransferredAnimation) {
-                    flags |= FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
-                }
                 if (record.mVoiceInteraction) {
                     flags |= FLAG_IS_VOICE_INTERACTION;
                 }
+                flags |= record.mTransitionChangeFlags;
             }
             final TaskFragment taskFragment = wc.asTaskFragment();
             if (taskFragment != null && task == null) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 383fcb9..07ae167 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -477,7 +477,10 @@
             }
             mLocalInsetsSourceProviders.remove(insetsTypes[i]);
         }
-        mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
+        // Update insets if this window is attached.
+        if (mDisplayContent != null) {
+            mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c96253c..ac720be 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1858,8 +1858,12 @@
             ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
                     + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
 
-            if ((win.isVisibleRequestedOrAdding() && displayContent.updateOrientation())
-                    || displayPolicy.updateDecorInsetsInfoIfNeeded(win)) {
+            boolean needToSendNewConfiguration =
+                    win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
+            if (win.providesNonDecorInsets()) {
+                needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
+            }
+            if (needToSendNewConfiguration) {
                 displayContent.sendNewConfiguration();
             }
 
@@ -2329,8 +2333,8 @@
                         & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
                     win.mLayoutNeeded = true;
                 }
-                if (layoutChanged) {
-                    configChanged = displayPolicy.updateDecorInsetsInfoIfNeeded(win);
+                if (layoutChanged && win.providesNonDecorInsets()) {
+                    configChanged = displayPolicy.updateDecorInsetsInfo();
                 }
                 if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
                         || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
@@ -6003,7 +6007,11 @@
         if (mFrozenDisplayId != INVALID_DISPLAY && mFrozenDisplayId == w.getDisplayId()
                 && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
             ProtoLog.v(WM_DEBUG_ORIENTATION, "Changing surface while display frozen: %s", w);
-            w.setOrientationChanging(true);
+            // WindowsState#reportResized won't tell invisible requested window to redraw,
+            // so do not set it as changing orientation to avoid affecting draw state.
+            if (w.isVisibleRequested()) {
+                w.setOrientationChanging(true);
+            }
             if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
                 mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 2e1477d..949fa96 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -46,6 +46,7 @@
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
 import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED;
+import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -242,8 +243,18 @@
     }
 
     @Override
-    public IBinder startTransition(int type, @Nullable IBinder transitionToken,
+    public IBinder startNewTransition(int type, @Nullable WindowContainerTransaction t) {
+        return startTransition(type, null /* transitionToken */, t);
+    }
+
+    @Override
+    public void startTransition(@NonNull IBinder transitionToken,
             @Nullable WindowContainerTransaction t) {
+        startTransition(-1 /* unused type */, transitionToken, t);
+    }
+
+    private IBinder startTransition(@WindowManager.TransitionType int type,
+            @Nullable IBinder transitionToken, @Nullable WindowContainerTransaction t) {
         enforceTaskPermission("startTransition()");
         final CallerInfo caller = new CallerInfo();
         final long ident = Binder.clearCallingIdentity();
@@ -1557,10 +1568,6 @@
         return (cfgChanges & CONTROLLABLE_CONFIGS) == 0;
     }
 
-    private void enforceTaskPermission(String func) {
-        mService.enforceTaskPermission(func);
-    }
-
     private boolean isValidTransaction(@NonNull WindowContainerTransaction t) {
         if (t.getTaskFragmentOrganizer() != null && !mTaskFragmentOrganizerController
                 .isOrganizerRegistered(t.getTaskFragmentOrganizer())) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 18ddaec..c161a9b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2043,9 +2043,13 @@
      * it must be drawn before allDrawn can become true.
      */
     boolean isInteresting() {
+        final RecentsAnimationController recentsAnimationController =
+                mWmService.getRecentsAnimationController();
         return mActivityRecord != null && !mAppDied
                 && (!mActivityRecord.isFreezingScreen() || !mAppFreezing)
-                && mViewVisibility == View.VISIBLE;
+                && mViewVisibility == View.VISIBLE
+                && (recentsAnimationController == null
+                         || recentsAnimationController.isInterestingForAllDrawn(this));
     }
 
     /**
@@ -2623,11 +2627,19 @@
                 }
             }
 
+            // Check if window provides non decor insets before clearing its provided insets.
+            final boolean windowProvidesNonDecorInsets = providesNonDecorInsets();
+
             removeImmediately();
             // 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)) {
+            boolean needToSendNewConfiguration = wasVisible && displayContent.updateOrientation();
+            if (windowProvidesNonDecorInsets) {
+                needToSendNewConfiguration |=
+                        displayContent.getDisplayPolicy().updateDecorInsetsInfo();
+            }
+
+            if (needToSendNewConfiguration) {
                 displayContent.sendNewConfiguration();
             }
             mWmService.updateFocusedWindowLocked(isFocused()
@@ -3857,8 +3869,8 @@
         // configuration update when the window has requested to be hidden. Doing so can lead to
         // the client erroneously accepting a configuration that would have otherwise caused an
         // activity restart. We instead hand back the last reported {@link MergedConfiguration}.
-        if (useLatestConfig || (relayoutVisible && (shouldCheckTokenVisibleRequested()
-                || mToken.isVisibleRequested()))) {
+        if (useLatestConfig || (relayoutVisible && (mActivityRecord == null
+                || mActivityRecord.mVisibleRequested))) {
             final Configuration globalConfig = getProcessGlobalConfiguration();
             final Configuration overrideConfig = getMergedOverrideConfiguration();
             outMergedConfiguration.setConfiguration(globalConfig, overrideConfig);
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 267cff6..4a51b83 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -351,6 +351,35 @@
             <xs:annotation name="nonnull"/>
             <xs:annotation name="final"/>
         </xs:element>
+        <xs:sequence>
+            <!--  Thresholds as tenths of percent of current brightness level, at each level of
+                brightness -->
+            <xs:element name="brightnessThresholdPoints" type="thresholdPoints" maxOccurs="1" minOccurs="0">
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="thresholdPoints">
+        <xs:sequence>
+            <xs:element type="thresholdPoint" name="brightnessThresholdPoint" maxOccurs="unbounded" minOccurs="1">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="thresholdPoint">
+        <xs:sequence>
+            <xs:element type="nonNegativeDecimal" name="threshold">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+            <xs:element type="nonNegativeDecimal" name="percentage">
+                <xs:annotation name="nonnull"/>
+                <xs:annotation name="final"/>
+            </xs:element>
+        </xs:sequence>
     </xs:complexType>
 
     <xs:complexType name="autoBrightness">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index f8bff75..748ef4b 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -13,7 +13,9 @@
 
   public class BrightnessThresholds {
     ctor public BrightnessThresholds();
+    method public final com.android.server.display.config.ThresholdPoints getBrightnessThresholdPoints();
     method @NonNull public final java.math.BigDecimal getMinimum();
+    method public final void setBrightnessThresholdPoints(com.android.server.display.config.ThresholdPoints);
     method public final void setMinimum(@NonNull java.math.BigDecimal);
   }
 
@@ -204,6 +206,19 @@
     method public final void setBrightnessThrottlingMap(@NonNull com.android.server.display.config.BrightnessThrottlingMap);
   }
 
+  public class ThresholdPoint {
+    ctor public ThresholdPoint();
+    method @NonNull public final java.math.BigDecimal getPercentage();
+    method @NonNull public final java.math.BigDecimal getThreshold();
+    method public final void setPercentage(@NonNull java.math.BigDecimal);
+    method public final void setThreshold(@NonNull java.math.BigDecimal);
+  }
+
+  public class ThresholdPoints {
+    ctor public ThresholdPoints();
+    method @NonNull public final java.util.List<com.android.server.display.config.ThresholdPoint> getBrightnessThresholdPoint();
+  }
+
   public class Thresholds {
     ctor public Thresholds();
     method @NonNull public final com.android.server.display.config.BrightnessThresholds getBrighteningThresholds();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6aca14f0..538d6bc 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7783,6 +7783,7 @@
         Preconditions.checkCallAuthorization(
                 isProfileOwner(caller) || isDefaultDeviceOwner(caller)
                         || hasCallingOrSelfPermission(permission.READ_NEARBY_STREAMING_POLICY));
+        Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userId));
 
         synchronized (getLockObject()) {
             if (mOwners.hasProfileOwner(userId) || mOwners.hasDeviceOwner()) {
@@ -7823,6 +7824,7 @@
         Preconditions.checkCallAuthorization(
                 isProfileOwner(caller) || isDefaultDeviceOwner(caller)
                         || hasCallingOrSelfPermission(permission.READ_NEARBY_STREAMING_POLICY));
+        Preconditions.checkCallAuthorization(hasCrossUsersPermission(caller, userId));
 
         synchronized (getLockObject()) {
             if (mOwners.hasProfileOwner(userId) || mOwners.hasDeviceOwner()) {
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 ed369c0..9c615d1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -764,13 +764,11 @@
     @Test
     public void testGetSystemPreferredDisplayMode() throws Exception {
         SurfaceControl.DisplayMode displayMode1 = createFakeDisplayMode(0, 1920, 1080, 60f);
-        // system preferred mode
+        // 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, displayMode3};
+                new SurfaceControl.DisplayMode[]{displayMode1, displayMode2};
         FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, 1);
         setUpDisplay(display);
         updateAvailableDisplays();
@@ -782,43 +780,24 @@
 
         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 system preferred mode
-        SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3, 2340, 1080, 20f);
-        modes = new SurfaceControl.DisplayMode[]{
-                displayMode1, displayMode2, displayMode3, addedDisplayInfo};
+        // Change the display and add new preferred mode
+        SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(2, 2340, 1080, 60f);
+        modes = new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, addedDisplayInfo};
         display.dynamicInfo.supportedDisplayModes = modes;
-        display.dynamicInfo.preferredBootDisplayMode = 3;
+        display.dynamicInfo.preferredBootDisplayMode = 2;
         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(3);
+        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
 
         DisplayDevice displayDevice = mListener.changedDisplays.get(0);
         displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 8280fc6..4f2b613 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -422,13 +422,13 @@
 
     @Test
     public void testHysteresisLevels() {
-        int[] ambientBrighteningThresholds = {100, 200};
-        int[] ambientDarkeningThresholds = {400, 500};
-        int[] ambientThresholdLevels = {500};
+        float[] ambientBrighteningThresholds = {50, 100};
+        float[] ambientDarkeningThresholds = {10, 20};
+        float[] ambientThresholdLevels = {0, 500};
         float ambientDarkeningMinChangeThreshold = 3.0f;
         float ambientBrighteningMinChangeThreshold = 1.5f;
         HysteresisLevels hysteresisLevels = new HysteresisLevels(ambientBrighteningThresholds,
-                ambientDarkeningThresholds, ambientThresholdLevels,
+                ambientDarkeningThresholds, ambientThresholdLevels, ambientThresholdLevels,
                 ambientDarkeningMinChangeThreshold, ambientBrighteningMinChangeThreshold);
 
         // test low, activate minimum change thresholds.
@@ -437,16 +437,17 @@
         assertEquals(1f, hysteresisLevels.getDarkeningThreshold(4.0f), EPSILON);
 
         // test max
-        assertEquals(12000f, hysteresisLevels.getBrighteningThreshold(10000.0f), EPSILON);
-        assertEquals(5000f, hysteresisLevels.getDarkeningThreshold(10000.0f), EPSILON);
+        // epsilon is x2 here, since the next floating point value about 20,000 is 0.0019531 greater
+        assertEquals(20000f, hysteresisLevels.getBrighteningThreshold(10000.0f), EPSILON * 2);
+        assertEquals(8000f, hysteresisLevels.getDarkeningThreshold(10000.0f), EPSILON);
 
         // test just below threshold
-        assertEquals(548.9f, hysteresisLevels.getBrighteningThreshold(499f), EPSILON);
-        assertEquals(299.4f, hysteresisLevels.getDarkeningThreshold(499f), EPSILON);
+        assertEquals(748.5f, hysteresisLevels.getBrighteningThreshold(499f), EPSILON);
+        assertEquals(449.1f, hysteresisLevels.getDarkeningThreshold(499f), EPSILON);
 
         // test at (considered above) threshold
-        assertEquals(600f, hysteresisLevels.getBrighteningThreshold(500f), EPSILON);
-        assertEquals(250f, hysteresisLevels.getDarkeningThreshold(500f), EPSILON);
+        assertEquals(1000f, hysteresisLevels.getBrighteningThreshold(500f), EPSILON);
+        assertEquals(400f, hysteresisLevels.getDarkeningThreshold(500f), EPSILON);
     }
 
     @Test
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 66420ad..a719f52 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayDeviceConfigTest.java
@@ -32,6 +32,8 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -48,6 +50,9 @@
 @RunWith(AndroidJUnit4.class)
 public final class DisplayDeviceConfigTest {
     private DisplayDeviceConfig mDisplayDeviceConfig;
+    private static final float ZERO_DELTA = 0.0f;
+    private static final float SMALL_DELTA = 0.0001f;
+
     @Mock
     private Context mContext;
 
@@ -69,26 +74,74 @@
         assertEquals(mDisplayDeviceConfig.getAmbientHorizonShort(), 50);
         assertEquals(mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis(), 3000);
         assertEquals(mDisplayDeviceConfig.getBrightnessRampIncreaseMaxMillis(), 2000);
-        assertEquals(mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(), 10.0f, 0.0f);
-        assertEquals(mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(), 2.0f, 0.0f);
-        assertEquals(mDisplayDeviceConfig.getBrightnessRampFastDecrease(), 0.01f, 0.0f);
-        assertEquals(mDisplayDeviceConfig.getBrightnessRampFastIncrease(), 0.02f, 0.0f);
-        assertEquals(mDisplayDeviceConfig.getBrightnessRampSlowIncrease(), 0.04f, 0.0f);
-        assertEquals(mDisplayDeviceConfig.getBrightnessRampSlowDecrease(), 0.03f, 0.0f);
-        assertEquals(mDisplayDeviceConfig.getBrightnessDefault(), 0.5f, 0.0f);
+        assertEquals(mDisplayDeviceConfig.getBrightnessRampFastDecrease(), 0.01f, ZERO_DELTA);
+        assertEquals(mDisplayDeviceConfig.getBrightnessRampFastIncrease(), 0.02f, ZERO_DELTA);
+        assertEquals(mDisplayDeviceConfig.getBrightnessRampSlowIncrease(), 0.04f, ZERO_DELTA);
+        assertEquals(mDisplayDeviceConfig.getBrightnessRampSlowDecrease(), 0.03f, ZERO_DELTA);
+        assertEquals(mDisplayDeviceConfig.getBrightnessDefault(), 0.5f, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getBrightness(), new float[]{0.0f, 0.62f, 1.0f},
-                0.0f);
-        assertArrayEquals(mDisplayDeviceConfig.getNits(), new float[]{2.0f, 500.0f, 800.0f}, 0.0f);
+                ZERO_DELTA);
+        assertArrayEquals(mDisplayDeviceConfig.getNits(), new float[]{2.0f, 500.0f, 800.0f},
+                ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getBacklight(), new float[]{0.0f, 0.62f, 1.0f},
-                0.0f);
-        assertEquals(mDisplayDeviceConfig.getScreenBrighteningMinThreshold(), 0.001, 0.000001f);
-        assertEquals(mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), 0.002, 0.000001f);
+                ZERO_DELTA);
         assertEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLightDebounce(), 2000);
         assertEquals(mDisplayDeviceConfig.getAutoBrightnessDarkeningLightDebounce(), 1000);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
-                float[]{0.0f, 50.0f, 80.0f}, 0.0f);
+                float[]{0.0f, 50.0f, 80.0f}, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
-                float[]{45.32f, 75.43f}, 0.0f);
+                float[]{45.32f, 75.43f}, ZERO_DELTA);
+
+        // Test thresholds
+        assertEquals(10, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(),
+                ZERO_DELTA);
+        assertEquals(20, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle(),
+                ZERO_DELTA);
+        assertEquals(30, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(), ZERO_DELTA);
+        assertEquals(40, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle(), ZERO_DELTA);
+
+        assertEquals(0.1f, mDisplayDeviceConfig.getScreenBrighteningMinThreshold(), ZERO_DELTA);
+        assertEquals(0.2f, mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle(), ZERO_DELTA);
+        assertEquals(0.3f, mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), ZERO_DELTA);
+        assertEquals(0.4f, mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 0.10f, 0.20f},
+                mDisplayDeviceConfig.getScreenBrighteningLevels(), ZERO_DELTA);
+        assertArrayEquals(new float[]{9, 10, 11},
+                mDisplayDeviceConfig.getScreenBrighteningPercentages(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 0.11f, 0.21f},
+                mDisplayDeviceConfig.getScreenDarkeningLevels(), ZERO_DELTA);
+        assertArrayEquals(new float[]{11, 12, 13},
+                mDisplayDeviceConfig.getScreenDarkeningPercentages(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 100, 200},
+                mDisplayDeviceConfig.getAmbientBrighteningLevels(), ZERO_DELTA);
+        assertArrayEquals(new float[]{13, 14, 15},
+                mDisplayDeviceConfig.getAmbientBrighteningPercentages(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 300, 400},
+                mDisplayDeviceConfig.getAmbientDarkeningLevels(), ZERO_DELTA);
+        assertArrayEquals(new float[]{15, 16, 17},
+                mDisplayDeviceConfig.getAmbientDarkeningPercentages(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 0.12f, 0.22f},
+                mDisplayDeviceConfig.getScreenBrighteningLevelsIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{17, 18, 19},
+                mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 0.13f, 0.23f},
+                mDisplayDeviceConfig.getScreenDarkeningLevelsIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{19, 20, 21},
+                mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 500, 600},
+                mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{21, 22, 23},
+                mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 700, 800},
+                mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{23, 24, 25},
+                mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA);
+
+
         // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
     }
@@ -97,9 +150,60 @@
     public void testConfigValuesFromConfigResource() {
         setupDisplayDeviceConfigFromConfigResourceFile();
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsNits(), new
-                float[]{2.0f, 200.0f, 600.0f}, 0.0f);
+                float[]{2.0f, 200.0f, 600.0f}, ZERO_DELTA);
         assertArrayEquals(mDisplayDeviceConfig.getAutoBrightnessBrighteningLevelsLux(), new
-                float[]{0.0f, 0.0f, 110.0f, 500.0f}, 0.0f);
+                float[]{0.0f, 0.0f, 110.0f, 500.0f}, ZERO_DELTA);
+
+        // Test thresholds
+        assertEquals(0, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThreshold(), ZERO_DELTA);
+        assertEquals(0, mDisplayDeviceConfig.getAmbientLuxBrighteningMinThresholdIdle(),
+                ZERO_DELTA);
+        assertEquals(0, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThreshold(), ZERO_DELTA);
+        assertEquals(0, mDisplayDeviceConfig.getAmbientLuxDarkeningMinThresholdIdle(), ZERO_DELTA);
+
+        assertEquals(0, mDisplayDeviceConfig.getScreenBrighteningMinThreshold(), ZERO_DELTA);
+        assertEquals(0, mDisplayDeviceConfig.getScreenBrighteningMinThresholdIdle(), ZERO_DELTA);
+        assertEquals(0, mDisplayDeviceConfig.getScreenDarkeningMinThreshold(), ZERO_DELTA);
+        assertEquals(0, mDisplayDeviceConfig.getScreenDarkeningMinThresholdIdle(), ZERO_DELTA);
+
+        // screen levels will be considered "old screen brightness scale"
+        // and therefore will divide by 255
+        assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
+                mDisplayDeviceConfig.getScreenBrighteningLevels(), SMALL_DELTA);
+        assertArrayEquals(new float[]{35, 36, 37},
+                mDisplayDeviceConfig.getScreenBrighteningPercentages(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
+                mDisplayDeviceConfig.getScreenDarkeningLevels(), SMALL_DELTA);
+        assertArrayEquals(new float[]{37, 38, 39},
+                mDisplayDeviceConfig.getScreenDarkeningPercentages(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 30, 31},
+                mDisplayDeviceConfig.getAmbientBrighteningLevels(), ZERO_DELTA);
+        assertArrayEquals(new float[]{27, 28, 29},
+                mDisplayDeviceConfig.getAmbientBrighteningPercentages(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 30, 31},
+                mDisplayDeviceConfig.getAmbientDarkeningLevels(), ZERO_DELTA);
+        assertArrayEquals(new float[]{29, 30, 31},
+                mDisplayDeviceConfig.getAmbientDarkeningPercentages(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
+                mDisplayDeviceConfig.getScreenBrighteningLevelsIdle(), SMALL_DELTA);
+        assertArrayEquals(new float[]{35, 36, 37},
+                mDisplayDeviceConfig.getScreenBrighteningPercentagesIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 42 / 255f, 43 / 255f},
+                mDisplayDeviceConfig.getScreenDarkeningLevelsIdle(), SMALL_DELTA);
+        assertArrayEquals(new float[]{37, 38, 39},
+                mDisplayDeviceConfig.getScreenDarkeningPercentagesIdle(), ZERO_DELTA);
+
+        assertArrayEquals(new float[]{0, 30, 31},
+                mDisplayDeviceConfig.getAmbientBrighteningLevelsIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{27, 28, 29},
+                mDisplayDeviceConfig.getAmbientBrighteningPercentagesIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{0, 30, 31},
+                mDisplayDeviceConfig.getAmbientDarkeningLevelsIdle(), ZERO_DELTA);
+        assertArrayEquals(new float[]{29, 30, 31},
+                mDisplayDeviceConfig.getAmbientDarkeningPercentagesIdle(), ZERO_DELTA);
+
         // Todo(brup): Add asserts for BrightnessThrottlingData, DensityMapping,
         // HighBrightnessModeData AmbientLightSensor, RefreshRateLimitations and ProximitySensor.
     }
@@ -154,11 +258,126 @@
                 +   "<ambientBrightnessChangeThresholds>\n"
                 +       "<brighteningThresholds>\n"
                 +           "<minimum>10</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>13</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>100</threshold><percentage>14</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>200</threshold><percentage>15</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
                 +       "</brighteningThresholds>\n"
                 +       "<darkeningThresholds>\n"
-                +           "<minimum>2</minimum>\n"
+                +           "<minimum>30</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>15</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>300</threshold><percentage>16</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>400</threshold><percentage>17</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
                 +       "</darkeningThresholds>\n"
                 +   "</ambientBrightnessChangeThresholds>\n"
+                +   "<displayBrightnessChangeThresholds>\n"
+                +       "<brighteningThresholds>\n"
+                +           "<minimum>0.1</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold>\n"
+                +                   "<percentage>9</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.10</threshold>\n"
+                +                   "<percentage>10</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.20</threshold>\n"
+                +                   "<percentage>11</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
+                +       "</brighteningThresholds>\n"
+                +       "<darkeningThresholds>\n"
+                +           "<minimum>0.3</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>11</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.11</threshold><percentage>12</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.21</threshold><percentage>13</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
+                +       "</darkeningThresholds>\n"
+                +   "</displayBrightnessChangeThresholds>\n"
+                +   "<ambientBrightnessChangeThresholdsIdle>\n"
+                +       "<brighteningThresholds>\n"
+                +           "<minimum>20</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>21</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>500</threshold><percentage>22</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>600</threshold><percentage>23</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
+                +       "</brighteningThresholds>\n"
+                +       "<darkeningThresholds>\n"
+                +           "<minimum>40</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>23</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>700</threshold><percentage>24</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>800</threshold><percentage>25</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
+                +       "</darkeningThresholds>\n"
+                +   "</ambientBrightnessChangeThresholdsIdle>\n"
+                +   "<displayBrightnessChangeThresholdsIdle>\n"
+                +       "<brighteningThresholds>\n"
+                +           "<minimum>0.2</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>17</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.12</threshold><percentage>18</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.22</threshold><percentage>19</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
+                +       "</brighteningThresholds>\n"
+                +       "<darkeningThresholds>\n"
+                +           "<minimum>0.4</minimum>\n"
+                +           "<brightnessThresholdPoints>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0</threshold><percentage>19</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.13</threshold><percentage>20</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +               "<brightnessThresholdPoint>\n"
+                +                   "<threshold>0.23</threshold><percentage>21</percentage>\n"
+                +               "</brightnessThresholdPoint>\n"
+                +           "</brightnessThresholdPoints>\n"
+                +       "</darkeningThresholds>\n"
+                +   "</displayBrightnessChangeThresholdsIdle>\n"
                 +   "<screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease> "
                 +   "<screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>  "
                 +   "<screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>"
@@ -171,18 +390,6 @@
                 +   "</screenBrightnessRampDecreaseMaxMillis>"
                 +   "<ambientLightHorizonLong>5000</ambientLightHorizonLong>\n"
                 +   "<ambientLightHorizonShort>50</ambientLightHorizonShort>\n"
-                +   "<displayBrightnessChangeThresholds>"
-                +       "<brighteningThresholds>"
-                +           "<minimum>"
-                +               "0.001"
-                +           "</minimum>"
-                +       "</brighteningThresholds>"
-                +       "<darkeningThresholds>"
-                +           "<minimum>"
-                +               "0.002"
-                +           "</minimum>"
-                +       "</darkeningThresholds>"
-                +   "</displayBrightnessChangeThresholds>"
                 +   "<screenBrightnessRampIncreaseMaxMillis>"
                 +       "2000"
                 +    "</screenBrightnessRampIncreaseMaxMillis>\n"
@@ -241,8 +448,24 @@
                 com.android.internal.R.array.config_autoBrightnessLevels))
                 .thenReturn(screenBrightnessLevelLux);
 
-        mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true);
+        // Thresholds
+        // Config.xml requires the levels arrays to be of length N and the thresholds arrays to be
+        // of length N+1
+        when(mResources.getIntArray(com.android.internal.R.array.config_ambientThresholdLevels))
+                .thenReturn(new int[]{30, 31});
+        when(mResources.getIntArray(com.android.internal.R.array.config_screenThresholdLevels))
+                .thenReturn(new int[]{42, 43});
+        when(mResources.getIntArray(
+                com.android.internal.R.array.config_ambientBrighteningThresholds))
+                .thenReturn(new int[]{270, 280, 290});
+        when(mResources.getIntArray(com.android.internal.R.array.config_ambientDarkeningThresholds))
+                .thenReturn(new int[]{290, 300, 310});
+        when(mResources.getIntArray(R.array.config_screenBrighteningThresholds))
+                .thenReturn(new int[]{350, 360, 370});
+        when(mResources.getIntArray(R.array.config_screenDarkeningThresholds))
+                .thenReturn(new int[]{370, 380, 390});
 
+        mDisplayDeviceConfig = DisplayDeviceConfig.create(mContext, true);
     }
 
     private TypedArray createFloatTypedArray(float[] vals) {
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..246aa90
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.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.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.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(deviceId, 0 /*generation*/, 0 /*controllerNumber*/,
+            "Device $deviceId" /*name*/, 0 /*vendorId*/, 0 /*productId*/, "descriptor$deviceId",
+            true /*isExternal*/, 0 /*sources*/, 0 /*keyboardType*/, null /*keyCharacterMap*/,
+            false /*hasVibrator*/, false /*hasMicrophone*/, false /*hasButtonUnderPad*/,
+            false /*hasSensor*/, true /*hasBattery*/)
+
+    @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/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 9ff7d69..2a6e6d8 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -731,7 +731,7 @@
         doAnswer(inv -> {
             when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
             return null;
-        }).when(mDreamManagerInternalMock).startDream(anyBoolean());
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
 
         setMinimumScreenOffTimeoutConfig(5);
         createService();
@@ -753,7 +753,7 @@
         doAnswer(inv -> {
             when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
             return null;
-        }).when(mDreamManagerInternalMock).startDream(anyBoolean());
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
 
         setMinimumScreenOffTimeoutConfig(5);
         createService();
@@ -1168,7 +1168,7 @@
         doAnswer(inv -> {
             when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
             return null;
-        }).when(mDreamManagerInternalMock).startDream(anyBoolean());
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
 
         final String pkg = mContextSpy.getOpPackageName();
         final Binder token = new Binder();
@@ -1662,7 +1662,7 @@
         forceDozing();
         // Allow handleSandman() to be called asynchronously
         advanceTime(500);
-        verify(mDreamManagerInternalMock).startDream(eq(true));
+        verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
     }
 
     @Test
@@ -1700,7 +1700,7 @@
 
         // Allow handleSandman() to be called asynchronously
         advanceTime(500);
-        verify(mDreamManagerInternalMock).startDream(eq(true));
+        verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
     }
 
     @Test
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 617a34f..91c2fe0 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -54,6 +54,7 @@
 import static org.mockito.Mockito.doThrow;
 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.verifyNoMoreInteractions;
@@ -83,7 +84,6 @@
 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;
@@ -101,6 +101,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.Spy;
 
 import java.time.LocalDateTime;
 import java.time.LocalTime;
@@ -137,8 +138,8 @@
     private PackageManager mPackageManager;
     @Mock
     private IBinder mBinder;
-    @Mock
-    private DreamManagerInternal mDreamManager;
+    @Spy
+    private TestInjector mInjector;
     @Captor
     private ArgumentCaptor<Intent> mOrderedBroadcastIntent;
     @Captor
@@ -207,10 +208,10 @@
         addLocalService(WindowManagerInternal.class, mWindowManager);
         addLocalService(PowerManagerInternal.class, mLocalPowerManager);
         addLocalService(TwilightManager.class, mTwilightManager);
-        addLocalService(DreamManagerInternal.class, mDreamManager);
-        
+
+        mInjector = spy(new TestInjector());
         mUiManagerService = new UiModeManagerService(mContext, /* setupWizardComplete= */ true,
-                mTwilightManager, new TestInjector());
+                mTwilightManager, mInjector);
         try {
             mUiManagerService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         } catch (SecurityException e) {/* ignore for permission denial */}
@@ -1321,84 +1322,53 @@
 
     @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();
+        verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
     }
 
     @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();
+        verify(mInjector, never()).startDreamWhenDockedIfAppropriate(mContext);
     }
 
     @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();
+        verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
     }
 
     @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();
+        verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
     }
 
     @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();
+        verify(mInjector).startDreamWhenDockedIfAppropriate(mContext);
     }
 
     private void triggerDockIntent() {
@@ -1435,22 +1405,6 @@
                 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);
@@ -1467,11 +1421,17 @@
         }
 
         public TestInjector(int callingUid) {
-          this.callingUid = callingUid;
+            this.callingUid = callingUid;
         }
 
+        @Override
         public int getCallingUid() {
             return callingUid;
         }
+
+        @Override
+        public void startDreamWhenDockedIfAppropriate(Context context) {
+            // do nothing
+        }
     }
 }
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 95e9f20..d544744 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2992,7 +2992,8 @@
                 .setSystemDecorations(true).build();
         // Add a decor insets provider window.
         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
-        squareDisplay.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(navbar);
+        assertTrue(navbar.providesNonDecorInsets()
+                && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo());
         squareDisplay.sendNewConfiguration();
         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
index 7fbf6bb..f6d5385 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ContentRecorderTests.java
@@ -289,6 +289,14 @@
     }
 
     @Test
+    public void testRemoveTask_stopsRecording_nullSessionShouldNotThrowExceptions() {
+        mContentRecorder.setContentRecordingSession(mTaskSession);
+        mContentRecorder.updateRecording();
+        mContentRecorder.setContentRecordingSession(null);
+        mTask.removeImmediately();
+    }
+
+    @Test
     public void testUpdateMirroredSurface_capturedAreaResized() {
         mContentRecorder.setContentRecordingSession(mDisplaySession);
         mContentRecorder.updateRecording();
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 e00296f..73eb127 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -292,12 +292,16 @@
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         final DisplayInfo di = mDisplayContent.getDisplayInfo();
         final int prevScreenHeightDp = mDisplayContent.getConfiguration().screenHeightDp;
-        assertTrue(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
+        assertTrue(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo());
         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));
+        assertFalse(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo());
+
+        navbar.removeIfPossible();
+        assertEquals(0, displayPolicy.getDecorInsetsInfo(di.rotation, di.logicalWidth,
+                di.logicalHeight).mNonDecorInsets.bottom);
     }
 
     @UseTestDisplay(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index adf694c..0462e1b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -30,6 +30,7 @@
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.os.Process.NOBODY_UID;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -1220,20 +1221,34 @@
 
     @Test
     public void testCreateRecentTaskInfo_detachedTask() {
-        final Task task = createTaskBuilder(".Task").setCreateActivity(true).build();
+        final Task task = createTaskBuilder(".Task").build();
+        new ActivityBuilder(mSupervisor.mService)
+                .setTask(task)
+                .setUid(NOBODY_UID)
+                .setComponent(getUniqueComponentName())
+                .build();
         final TaskDisplayArea tda = task.getDisplayArea();
 
         assertTrue(task.isAttached());
         assertTrue(task.supportsMultiWindow());
 
-        RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true);
+        RecentTaskInfo info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+                true /* getTasksAllowed */);
 
         assertTrue(info.supportsMultiWindow);
 
+        info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+                false /* getTasksAllowed */);
+
+        assertTrue(info.topActivity == null);
+        assertTrue(info.topActivityInfo == null);
+        assertTrue(info.baseActivity == null);
+
         // The task can be put in split screen even if it is not attached now.
         task.removeImmediately();
 
-        info = mRecentTasks.createRecentTaskInfo(task, true);
+        info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+                true /* getTasksAllowed */);
 
         assertTrue(info.supportsMultiWindow);
 
@@ -1242,7 +1257,8 @@
         doReturn(false).when(tda).supportsNonResizableMultiWindow();
         doReturn(false).when(task).isResizeable();
 
-        info = mRecentTasks.createRecentTaskInfo(task, true);
+        info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+                true /* getTasksAllowed */);
 
         assertFalse(info.supportsMultiWindow);
 
@@ -1250,7 +1266,8 @@
         // the device supports it.
         doReturn(true).when(tda).supportsNonResizableMultiWindow();
 
-        info = mRecentTasks.createRecentTaskInfo(task, true);
+        info = mRecentTasks.createRecentTaskInfo(task, true /* stripExtras */,
+                true /* getTasksAllowed */);
 
         assertTrue(info.supportsMultiWindow);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 6128428..b46e90d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -1312,13 +1312,15 @@
         secondActivity.app.setThread(null);
         // This should do nothing from a non-attached caller.
         assertFalse(task.navigateUpTo(secondActivity /* source record */,
-                firstActivity.intent /* destIntent */, null /* destGrants */,
-                0 /* resultCode */, null /* resultData */, null /* resultGrants */));
+                firstActivity.intent /* destIntent */, null /* resolvedType */,
+                null /* destGrants */, 0 /* resultCode */, null /* resultData */,
+                null /* resultGrants */));
 
         secondActivity.app.setThread(thread);
         assertTrue(task.navigateUpTo(secondActivity /* source record */,
-                firstActivity.intent /* destIntent */, null /* destGrants */,
-                0 /* resultCode */, null /* resultData */, null /* resultGrants */));
+                firstActivity.intent /* destIntent */, null /* resolvedType */,
+                null /* destGrants */, 0 /* resultCode */, null /* resultData */,
+                null /* resultGrants */));
         // The firstActivity uses default launch mode, so the activities between it and itself will
         // be finished.
         assertTrue(secondActivity.finishing);
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 1404de2..0b23359 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -195,6 +195,7 @@
         mController.onTaskFragmentAppeared(mTaskFragment.getTaskFragmentOrganizer(), mTaskFragment);
         mController.dispatchPendingEvents();
 
+        assertTaskFragmentParentInfoChangedTransaction(mTask);
         assertTaskFragmentAppearedTransaction();
     }
 
@@ -365,6 +366,7 @@
         mController.onActivityReparentedToTask(activity);
         mController.dispatchPendingEvents();
 
+        assertTaskFragmentParentInfoChangedTransaction(task);
         assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token);
     }
 
@@ -1205,7 +1207,8 @@
 
     /**
      * Creates a {@link TaskFragment} with the {@link WindowContainerTransaction}. Calls
-     * {@link WindowOrganizerController#applyTransaction} to apply the transaction,
+     * {@link WindowOrganizerController#applyTransaction(WindowContainerTransaction)} to apply the
+     * transaction,
      */
     private void createTaskFragmentFromOrganizer(WindowContainerTransaction wct,
             ActivityRecord ownerActivity, IBinder fragmentToken) {
@@ -1239,8 +1242,8 @@
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
         assertFalse(changes.isEmpty());
 
-        // Appeared will come with parent info changed.
-        final TaskFragmentTransaction.Change change = changes.get(changes.size() - 1);
+        // Use remove to verify multiple transaction changes.
+        final TaskFragmentTransaction.Change change = changes.remove(0);
         assertEquals(TYPE_TASK_FRAGMENT_APPEARED, change.getType());
         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
         assertEquals(mFragmentToken, change.getTaskFragmentToken());
@@ -1253,8 +1256,8 @@
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
         assertFalse(changes.isEmpty());
 
-        // InfoChanged may come with parent info changed.
-        final TaskFragmentTransaction.Change change = changes.get(changes.size() - 1);
+        // Use remove to verify multiple transaction changes.
+        final TaskFragmentTransaction.Change change = changes.remove(0);
         assertEquals(TYPE_TASK_FRAGMENT_INFO_CHANGED, change.getType());
         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
         assertEquals(mFragmentToken, change.getTaskFragmentToken());
@@ -1266,7 +1269,9 @@
         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
         assertFalse(changes.isEmpty());
-        final TaskFragmentTransaction.Change change = changes.get(0);
+
+        // Use remove to verify multiple transaction changes.
+        final TaskFragmentTransaction.Change change = changes.remove(0);
         assertEquals(TYPE_TASK_FRAGMENT_VANISHED, change.getType());
         assertEquals(mTaskFragmentInfo, change.getTaskFragmentInfo());
         assertEquals(mFragmentToken, change.getTaskFragmentToken());
@@ -1278,7 +1283,9 @@
         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
         assertFalse(changes.isEmpty());
-        final TaskFragmentTransaction.Change change = changes.get(0);
+
+        // Use remove to verify multiple transaction changes.
+        final TaskFragmentTransaction.Change change = changes.remove(0);
         assertEquals(TYPE_TASK_FRAGMENT_PARENT_INFO_CHANGED, change.getType());
         assertEquals(task.mTaskId, change.getTaskId());
         assertEquals(task.getTaskFragmentParentInfo(), change.getTaskFragmentParentInfo());
@@ -1290,7 +1297,9 @@
         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
         assertFalse(changes.isEmpty());
-        final TaskFragmentTransaction.Change change = changes.get(0);
+
+        // Use remove to verify multiple transaction changes.
+        final TaskFragmentTransaction.Change change = changes.remove(0);
         assertEquals(TYPE_TASK_FRAGMENT_ERROR, change.getType());
         assertEquals(mErrorToken, change.getErrorCallbackToken());
         final Bundle errorBundle = change.getErrorBundle();
@@ -1306,7 +1315,9 @@
         final TaskFragmentTransaction transaction = mTransactionCaptor.getValue();
         final List<TaskFragmentTransaction.Change> changes = transaction.getChanges();
         assertFalse(changes.isEmpty());
-        final TaskFragmentTransaction.Change change = changes.get(0);
+
+        // Use remove to verify multiple transaction changes.
+        final TaskFragmentTransaction.Change change = changes.remove(0);
         assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType());
         assertEquals(taskId, change.getTaskId());
         assertEquals(intent, change.getActivityIntent());
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 76cd19b..68ac1d6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -1454,6 +1454,21 @@
         verify(tfBehind, never()).resumeTopActivity(any(), any(), anyBoolean());
     }
 
+    @Test
+    public void testGetTaskFragment() {
+        final Task parentTask = createTask(mDisplayContent);
+        final TaskFragment tf0 = createTaskFragmentWithParentTask(parentTask);
+        final TaskFragment tf1 = createTaskFragmentWithParentTask(parentTask);
+
+        assertNull("Could not find it because there's no organized TaskFragment",
+                parentTask.getTaskFragment(TaskFragment::isOrganizedTaskFragment));
+
+        doReturn(true).when(tf0).isOrganizedTaskFragment();
+
+        assertEquals("tf0 must be return because it's the organized TaskFragment.",
+                tf0, parentTask.getTaskFragment(TaskFragment::isOrganizedTaskFragment));
+    }
+
     private Task getTestTask() {
         final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
         return task.getBottomMostTask();
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 45d8e22..7342c49 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -19,7 +19,6 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
@@ -393,6 +392,70 @@
     }
 
     @Test
+    public void testCreateInfo_PromoteSimilarClose() {
+        final Transition transition = createTestTransition(TRANSIT_CLOSE);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task topTask = createTask(mDisplayContent);
+        final Task belowTask = createTask(mDisplayContent);
+        final ActivityRecord showing = createActivityRecord(belowTask);
+        final ActivityRecord hiding = createActivityRecord(topTask);
+        final ActivityRecord closing = createActivityRecord(topTask);
+        // Start states.
+        changes.put(topTask, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+        changes.put(belowTask, new Transition.ChangeInfo(false /* vis */, false /* exChg */));
+        changes.put(showing, new Transition.ChangeInfo(false /* vis */, false /* exChg */));
+        changes.put(hiding, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+        changes.put(closing, new Transition.ChangeInfo(true /* vis */, true /* exChg */));
+        fillChangeMap(changes, topTask);
+        // End states.
+        showing.mVisibleRequested = true;
+        closing.mVisibleRequested = false;
+        hiding.mVisibleRequested = false;
+
+        participants.add(belowTask);
+        participants.add(hiding);
+        participants.add(closing);
+        ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+        assertEquals(2, targets.size());
+        assertTrue(targets.contains(belowTask));
+        assertTrue(targets.contains(topTask));
+    }
+
+    @Test
+    public void testCreateInfo_PromoteSimilarOpen() {
+        final Transition transition = createTestTransition(TRANSIT_OPEN);
+        ArrayMap<WindowContainer, Transition.ChangeInfo> changes = transition.mChanges;
+        ArraySet<WindowContainer> participants = transition.mParticipants;
+
+        final Task topTask = createTask(mDisplayContent);
+        final Task belowTask = createTask(mDisplayContent);
+        final ActivityRecord showing = createActivityRecord(topTask);
+        final ActivityRecord opening = createActivityRecord(topTask);
+        final ActivityRecord closing = createActivityRecord(belowTask);
+        // Start states.
+        changes.put(topTask, new Transition.ChangeInfo(false /* vis */, false /* exChg */));
+        changes.put(belowTask, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+        changes.put(showing, new Transition.ChangeInfo(false /* vis */, false /* exChg */));
+        changes.put(opening, new Transition.ChangeInfo(false /* vis */, true /* exChg */));
+        changes.put(closing, new Transition.ChangeInfo(true /* vis */, false /* exChg */));
+        fillChangeMap(changes, topTask);
+        // End states.
+        showing.mVisibleRequested = true;
+        opening.mVisibleRequested = true;
+        closing.mVisibleRequested = false;
+
+        participants.add(belowTask);
+        participants.add(showing);
+        participants.add(opening);
+        ArrayList<WindowContainer> targets = Transition.calculateTargets(participants, changes);
+        assertEquals(2, targets.size());
+        assertTrue(targets.contains(belowTask));
+        assertTrue(targets.contains(topTask));
+    }
+
+    @Test
     public void testTargets_noIntermediatesToWallpaper() {
         final Transition transition = createTestTransition(TRANSIT_OPEN);
 
@@ -732,6 +795,11 @@
         assertTrue(asyncRotationController.isTargetToken(decorToken));
         assertShouldFreezeInsetsPosition(asyncRotationController, statusBar, true);
 
+        if (TransitionController.SYNC_METHOD != BLASTSyncEngine.METHOD_BLAST) {
+            // Only seamless window syncs its draw transaction with transition.
+            assertFalse(asyncRotationController.handleFinishDrawing(statusBar, mMockT));
+            assertTrue(asyncRotationController.handleFinishDrawing(screenDecor, mMockT));
+        }
         screenDecor.setOrientationChanging(false);
         // Status bar finishes drawing before the start transaction. Its fade-in animation will be
         // executed until the transaction is committed, so it is still in target tokens.
@@ -1160,10 +1228,8 @@
         final ArraySet<WindowContainer> participants = transition.mParticipants;
 
         final Task task = createTask(mDisplayContent);
-        // Set to multi-windowing mode in order to set bounds.
-        task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
         final Rect taskBounds = new Rect(0, 0, 500, 1000);
-        task.setBounds(taskBounds);
+        task.getConfiguration().windowConfiguration.setBounds(taskBounds);
         final ActivityRecord nonEmbeddedActivity = createActivityRecord(task);
         final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
         mAtm.mTaskFragmentOrganizerController.registerOrganizer(
@@ -1205,10 +1271,8 @@
         final ArraySet<WindowContainer> participants = transition.mParticipants;
 
         final Task task = createTask(mDisplayContent);
-        // Set to multi-windowing mode in order to set bounds.
-        task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
         final Rect taskBounds = new Rect(0, 0, 500, 1000);
-        task.setBounds(taskBounds);
+        task.getConfiguration().windowConfiguration.setBounds(taskBounds);
         final ActivityRecord activity = createActivityRecord(task);
         // Start states: set bounds to make sure the start bounds is ignored if it is not visible.
         activity.getConfiguration().windowConfiguration.setBounds(new Rect(0, 0, 250, 500));
@@ -1236,10 +1300,8 @@
         final ArraySet<WindowContainer> participants = transition.mParticipants;
 
         final Task task = createTask(mDisplayContent);
-        // Set to multi-windowing mode in order to set bounds.
-        task.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
         final Rect taskBounds = new Rect(0, 0, 500, 1000);
-        task.setBounds(taskBounds);
+        task.getConfiguration().windowConfiguration.setBounds(taskBounds);
         final ActivityRecord activity = createActivityRecord(task);
         // Start states: fills Task without override.
         activity.mVisibleRequested = true;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index b8da8cc..b0d7ed6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -43,6 +43,7 @@
 
 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.assertNull;
 import static org.mockito.ArgumentMatchers.any;
@@ -195,14 +196,31 @@
         mWm.mWindowMap.put(win.mClient.asBinder(), win);
         final int w = 100;
         final int h = 200;
+        final ClientWindowFrames outFrames = new ClientWindowFrames();
+        final MergedConfiguration outConfig = new MergedConfiguration();
+        final SurfaceControl outSurfaceControl = new SurfaceControl();
+        final InsetsState outInsetsState = new InsetsState();
+        final InsetsSourceControl[] outControls = new InsetsSourceControl[0];
+        final Bundle outBundle = new Bundle();
         mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.GONE, 0, 0, 0,
-                new ClientWindowFrames(), new MergedConfiguration(), new SurfaceControl(),
-                new InsetsState(), new InsetsSourceControl[0], new Bundle());
+                outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
         // Because the window is already invisible, it doesn't need to apply exiting animation
         // and WMS#tryStartExitingAnimation() will destroy the surface directly.
         assertFalse(win.mAnimatingExit);
         assertFalse(win.mHasSurface);
         assertNull(win.mWinAnimator.mSurfaceController);
+
+        doReturn(mSystemServicesTestRule.mTransaction).when(SurfaceControl::getGlobalTransaction);
+        // Invisible requested activity should not get the last config even if its view is visible.
+        mWm.relayoutWindow(win.mSession, win.mClient, win.mAttrs, w, h, View.VISIBLE, 0, 0, 0,
+                outFrames, outConfig, outSurfaceControl, outInsetsState, outControls, outBundle);
+        assertEquals(0, outConfig.getMergedConfiguration().densityDpi);
+        // Non activity window can still get the last config.
+        win.mActivityRecord = null;
+        win.fillClientWindowFramesAndConfiguration(outFrames, outConfig,
+                false /* useLatestConfig */, true /* relayoutVisible */);
+        assertEquals(win.getConfiguration().densityDpi,
+                outConfig.getMergedConfiguration().densityDpi);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index cfc0da7..9bcc136 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -731,6 +731,15 @@
         assertTrue(mWm.mResizingWindows.contains(startingApp));
         assertTrue(startingApp.isDrawn());
         assertFalse(startingApp.getOrientationChanging());
+
+        // Even if the display is frozen, invisible requested window should not be affected.
+        startingApp.mActivityRecord.mVisibleRequested = false;
+        mWm.startFreezingDisplay(0, 0, mDisplayContent);
+        doReturn(true).when(mWm.mPolicy).isScreenOn();
+        startingApp.getWindowFrames().setInsetsChanged(true);
+        startingApp.updateResizingWindowIfNeeded();
+        assertTrue(startingApp.isDrawn());
+        assertFalse(startingApp.getOrientationChanging());
     }
 
     @UseTestDisplay(addWindows = W_ABOVE_ACTIVITY)
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 ef532f5..b99fd16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -718,6 +718,10 @@
         activity.mVisibleRequested = true;
     }
 
+    static TaskFragment createTaskFragmentWithParentTask(@NonNull Task parentTask) {
+        return createTaskFragmentWithParentTask(parentTask, false /* createEmbeddedTask */);
+    }
+
     /**
      * Creates a {@link TaskFragment} and attach it to the {@code parentTask}.
      *
@@ -1727,7 +1731,7 @@
         }
 
         void startTransition() {
-            mOrganizer.startTransition(mLastRequest.getType(), mLastTransit, null);
+            mOrganizer.startTransition(mLastTransit, null);
         }
 
         void onTransactionReady(SurfaceControl.Transaction t) {
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 7eec86a..0fdf40d 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -23,6 +23,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Locale;
 
 /**
  * Contains access network related constants.
@@ -114,7 +115,7 @@
 
         /** @hide */
         public static @RadioAccessNetworkType int fromString(@NonNull String str) {
-            switch (str.toUpperCase()) {
+            switch (str.toUpperCase(Locale.ROOT)) {
                 case "UNKNOWN": return UNKNOWN;
                 case "GERAN": return GERAN;
                 case "UTRAN": return UTRAN;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
new file mode 100644
index 0000000..efb92f2
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.provider.Settings
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.Assert.assertNotNull
+
+class AssistantAppHelper @JvmOverloads constructor(
+    val instr: Instrumentation,
+    val component: ComponentName = ActivityOptions.ASSISTANT_SERVICE_COMPONENT_NAME,
+) {
+    protected val uiDevice: UiDevice = UiDevice.getInstance(instr)
+    protected val defaultAssistant: String? = Settings.Secure.getString(
+        instr.targetContext.contentResolver,
+        Settings.Secure.ASSISTANT)
+    protected val defaultVoiceInteractionService: String? = Settings.Secure.getString(
+        instr.targetContext.contentResolver,
+        Settings.Secure.VOICE_INTERACTION_SERVICE)
+
+    fun setDefaultAssistant() {
+        Settings.Secure.putString(
+            instr.targetContext.contentResolver,
+            Settings.Secure.VOICE_INTERACTION_SERVICE,
+            component.flattenToString())
+        Settings.Secure.putString(
+            instr.targetContext.contentResolver,
+            Settings.Secure.ASSISTANT,
+            component.flattenToString())
+    }
+
+    fun resetDefaultAssistant() {
+        Settings.Secure.putString(
+            instr.targetContext.contentResolver,
+            Settings.Secure.VOICE_INTERACTION_SERVICE,
+            defaultVoiceInteractionService)
+        Settings.Secure.putString(
+            instr.targetContext.contentResolver,
+            Settings.Secure.ASSISTANT,
+            defaultAssistant)
+    }
+
+    /**
+     * Open Assistance UI.
+     *
+     * @param longpress open the UI by long pressing power button.
+     *  Otherwise open the UI through vioceinteraction shell command directly.
+     */
+    @JvmOverloads
+    fun openUI(longpress: Boolean = false) {
+        if (longpress) {
+            uiDevice.executeShellCommand("input keyevent --longpress KEYCODE_POWER")
+        } else {
+            uiDevice.executeShellCommand("cmd voiceinteraction show")
+        }
+        val ui = uiDevice.wait(
+            Until.findObject(By.res(ActivityOptions.FLICKER_APP_PACKAGE, "vis_frame")),
+            FIND_TIMEOUT)
+        assertNotNull("Can't find Assistant UI after long pressing power button.", ui)
+    }
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index d11ca49..fa83f22 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -64,7 +64,7 @@
         wmHelper: WindowManagerStateHelper,
         direction: Direction
     ): Boolean {
-        val ratioForScreenBottom = 0.97
+        val ratioForScreenBottom = 0.99
         val fullView = wmHelper.getWindowRegion(component)
         require(!fullView.isEmpty) { "Target $component view not found." }
 
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 45a4730..e90eed1 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
@@ -80,20 +80,21 @@
 
     public static final String SHOW_WHEN_LOCKED_ACTIVITY_LAUNCHER_NAME = "ShowWhenLockedApp";
     public static final ComponentName SHOW_WHEN_LOCKED_ACTIVITY_COMPONENT_NAME =
-            new ComponentName(FLICKER_APP_PACKAGE,
-                    FLICKER_APP_PACKAGE + ".ShowWhenLockedActivity");
+            new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".ShowWhenLockedActivity");
 
     public static final String NOTIFICATION_ACTIVITY_LAUNCHER_NAME = "NotificationApp";
     public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
-            new ComponentName(FLICKER_APP_PACKAGE,
-                    FLICKER_APP_PACKAGE + ".NotificationActivity");
+            new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".NotificationActivity");
 
     public static final String MAIL_ACTIVITY_LAUNCHER_NAME = "MailActivity";
-    public static final ComponentName MAIL_ACTIVITY_COMPONENT_NAME = new ComponentName(
-            FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".MailActivity");
+    public static final ComponentName MAIL_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".MailActivity");
 
     public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
     public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
-            new ComponentName(FLICKER_APP_PACKAGE,
-                   FLICKER_APP_PACKAGE + ".GameActivity");
+            new ComponentName(FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".GameActivity");
+
+    public static final ComponentName ASSISTANT_SERVICE_COMPONENT_NAME =
+            new ComponentName(
+                    FLICKER_APP_PACKAGE, FLICKER_APP_PACKAGE + ".AssistantInteractionService");
 }